linux 多线程编程.docx
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_05.gif)
《linux 多线程编程.docx》由会员分享,可在线阅读,更多相关《linux 多线程编程.docx(13页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、C语言中,信号量的数据类型为结构sem_t,它本质上是一个长整型的数。thread1.c#include #include #include void *thread_function(void *arg) int i; for ( i=0; i20; i+) printf(Thread says hi!n); sleep(1); return NULL;int main(void) pthread_t mythread; if ( pthread_create( &mythread, NULL, thread_function, NULL) ) printf(error creating t
2、hread.); abort(); if ( pthread_join ( mythread, NULL ) ) printf(error joining thread.); abort(); exit(0);要编译这个程序,只需先将程序存为 thread1.c,然后输入:$ gcc thread1.c -o thread1 -lpthread运行则输入:$ ./thread1理解 thread1.cthread1.c 是一个非常简单的线程程序。虽然它没有实现什么有用的功能,但可以帮助理解线程的运行机制。下面,我们一步一步地了解这个程序是干什么的。main() 中声明了变量 mythread,
3、类型是 pthread_t。pthread_t 类型在 pthread.h 中定义,通常称为“线程 id”(缩写为 tid)。可以认为它是一种线程句柄。mythread 声明后(记住 mythread 只是一个 tid,或是将要创建的线程的句柄),调用 pthread_create 函数创建一个真实活动的线程。不要因为 pthread_create() 在 if 语句内而受其迷惑。由于 pthread_create() 执行成功时返回零而失败时则返回非零值,将 pthread_create() 函数调用放在 if() 语句中只是为了方便地检测失败的调用。让我们查看一下 pthread_crea
4、te 参数。第一个参数 &mythread 是指向 mythread 的指针。第二个参数当前为 NULL,可用来定义线程的某些属性。由于缺省的线程属性是适用的,只需将该参数设为 NULL。第三个参数是新线程启动时调用的函数名。本例中,函数名为 thread_function()。当 thread_function() 返回时,新线程将终止。本例中,线程函数没有实现大的功能。它仅将 Thread says hi! 输出 20 次然后退出。注意 thread_function() 接受 void * 作为参数,同时返回值的类型也是 void *。这表明可以用 void * 向新线程传递任意类型的数
5、据,新线程完成时也可返回任意类型的数据。那如何向线程传递一个任意参数?很简单。只要利用 pthread_create() 中的第四个参数。本例中,因为没有必要将任何数据传给微不足道的 thread_function(),所以将第四个参数设为 NULL。您也许已推测到,在 pthread_create() 成功返回之后,程序将包含两个线程。等一等,两个线程?我们不是只创建了一个线程吗?不错,我们只创建了一个进程。但是主程序同样也是一个线程。可以这样理解:如果编写的程序根本没有使用 POSIX 线程,则该程序是单线程的(这个单线程称为“主”线程)。创建一个新线程之后程序总共就有两个线程了。我想此时
6、您至少有两个重要问题。第一个问题,新线程创建之后主线程如何运行。答案,主线程按顺序继续执行下一行程序(本例中执行 if (pthread_join(.))。第二个问题,新线程结束时如何处理。答案,新线程先停止,然后作为其清理过程的一部分,等待与另一个线程合并或“连接”。现在,来看一下 pthread_join()。正如 pthread_create() 将一个线程拆分为两个, pthread_join() 将两个线程合并为一个线程。pthread_join() 的第一个参数是 tid mythread。第二个参数是指向 void 指针的指针。如果 void 指针不为 NULL,pthread_
7、join 将线程的 void * 返回值放置在指定的位置上。由于我们不必理会 thread_function() 的返回值,所以将其设为 NULL.您会注意到 thread_function() 花了 20 秒才完成。在 thread_function() 结束很久之前,主线程就已经调用了 pthread_join()。如果发生这种情况,主线程将中断(转向睡眠)然后等待 thread_function() 完成。当 thread_function() 完成后, pthread_join() 将返回。这时程序又只有一个主线程。当程序退出时,所有新线程已经使用 pthread_join() 合并了
8、。这就是应该如何处理在程序中创建的每个新线程的过程。如果没有合并一个新线程,则它仍然对系统的最大线程数限制不利。这意味着如果未对线程做正确的清理,最终会导致 pthread_create() 调用失败。thread2.c 的代码如下:thread2.c#include #include #include #include int myglobal; void *thread_function(void *arg) int i,j; for ( i=0; i20; i+) j=myglobal; j=j+1; printf(.); fflush(stdout); sleep(1); myglob
9、al=j; return NULL;int main(void) pthread_t mythread; int i; if ( pthread_create( &mythread, NULL, thread_function, NULL) ) printf(error creating thread.); abort(); for ( i=0; i20; i+) myglobal=myglobal+1; printf(o); fflush(stdout); sleep(1); if ( pthread_join ( mythread, NULL ) ) printf(error joinin
10、g thread.); abort(); printf(nmyglobal equals %dn,myglobal); exit(0);理解 thread2.c如同第一个程序,这个程序创建一个新线程。主线程和新线程都将全局变量 myglobal 加一 20 次。但是程序本身产生了某些意想不到的结果。编译代码请输入:$ gcc thread2.c -o thread2 -lpthread运行请输入:$ ./thread2输出:$ ./thread2.o.o.o.o.oo.o.o.o.o.o.o.o.o.o.o.o.o.o.omyglobal equals 21非常意外吧!因为 myglobal
11、从零开始,主线程和新线程各自对其进行了 20 次加一, 程序结束时 myglobal 值应当等于 40。由于 myglobal 输出结果为 21,这其中肯定有问题。首先查看函数 thread_function()。注意如何将 myglobal 复制到局部变量 j 了吗? 接着将 j 加一, 再睡眠一秒,然后到这时才将新的 j 值复制到 myglobal?这就是关键所在。设想一下,如果主线程就在新线程将 myglobal 值复制给 j后立即将 myglobal 加一,会发生什么?当 thread_function() 将 j 的值写回 myglobal 时,就覆盖了主线程所做的修改。thread
12、3.c#include #include #include #include int myglobal;pthread_mutex_t mymutex=PTHREAD_MUTEX_INITIALIZER;void *thread_function(void *arg) int i,j; for ( i=0; i20; i+) pthread_mutex_lock(&mymutex); j=myglobal; j=j+1; printf(.); fflush(stdout); sleep(1); myglobal=j; pthread_mutex_unlock(&mymutex); return
13、 NULL;int main(void) pthread_t mythread; int i; if ( pthread_create( &mythread, NULL, thread_function, NULL) ) printf(error creating thread.); abort(); for ( i=0; i20; i+) pthread_mutex_lock(&mymutex); myglobal=myglobal+1; pthread_mutex_unlock(&mymutex); printf(o); fflush(stdout); sleep(1); if ( pth
14、read_join ( mythread, NULL ) ) printf(error joining thread.); abort(); printf(nmyglobal equals %dn,myglobal); exit(0);输出:o.ooooooooooooooooooomyglobal equals 40pthread_cond_wait()用于阻塞当前线程,等待别的线程使用pthread_cond_signal()或pthread_cond_broadcast来唤醒它。pthread_cond_wait()必须与pthread_mutex 配套使用。pthread_cond_w
15、ait()函数一进入wait状态就会自动release mutex。当其他线程通过pthread_cond_signal()或pthread_cond_broadcast,把该线程唤醒,使pthread_cond_wait()通过(返回)时,该线程又自动获得该mutex。pthread_cond_signal函数的作用是发送一个信号给另外一个正在处于阻塞等待状态的线程,使其脱离阻塞状态,继续执行.如果没有线程处在阻塞等待状态,pthread_cond_signal也会成功返回。pthread_cond_signal只能唤醒已经处于pthread_cond_wait的线程 也就是说,如果sign
16、al的时候没有线程在condition wait,那么本次signal就没有效果,后续的线程进入condition wait之后,无法被之前的signal唤醒。 使用pthread_cond_signal一般不会有“惊群现象”产生,他最多只给一个线程发信号。假如有多个线程正在阻塞等待着这个条件变量的话,那么是根据各等待线程优先级的高低确定哪个线程接收到信号开始继续执行。如果各线程优先级相同,则根据等待时间的长短来确定哪个线程获得信号。但无论如何一个pthread_cond_signal调用最多发信一次。但是pthread_cond_signal在多处理器上可能同时唤醒多个线程,当你只能让一个线
17、程处理某个任务时,其它被唤醒的线程就需要继续 wait,而且规范要求pthread_cond_signal至少唤醒一个pthread_cond_wait上的线程,其实有些实现为了简单在单处理器上也会唤醒多个线程. 另外,某些应用,如线程池,pthread_cond_broadcast唤醒全部线程,但我们通常只需要一部分线程去做执行任务,所以其它的线程需要继续wait.所以强烈推荐对pthread_cond_wait()使用while循环来做条件判断.图 4. 采用 Linux 条件变量模型的出租车实例流程通过对比结果,你会发现同样的逻辑,在 Linux 平台上运行的结果却完全是两样。对于在 W
18、indows 平台上的模型一, Jack 开着出租车到了站台,触发条件变量。如果没顾客,条件变量将维持触发状态,也就是说 Jack 停下车在那里等着。直到 Susan 小姐来了站台,执行等待条件来找出租车。 Susan 搭上 Jack 的出租车离开,同时条件变量被自动复位。但是到了 Linux 平台,问题就来了,Jack 到了站台一看没人,触发的条件变量被直接复位,于是 Jack 排在等待队列里面。来迟一秒的 Susan 小姐到了站台却看不到在那里等待的 Jack,只能等待,直到 Mike 开车赶到,重新触发条件变量,Susan 才上了 Mike 的车。这对于在排队系统前面的 Jack 是不公
19、平的,而问题症结是在于 Linux 平台上条件变量触发的自动复位引起的一个 Bug 。条件变量在 Linux 平台上的这种模型很难说好坏。但是在实际开发中,我们可以对代码稍加改进就可以避免这种差异的发生。由于这种差异只发生在触发没有被线程等待在条件变量的时刻,因此我们只需要掌握好触发的时机即可。最简单的做法是增加一个计数器记录等待线程的个数,在决定触发条件变量前检查下该变量即可。改进后 Linux 函数如清单 5 所示。清单 5. Linux 出租车案例代码实例 / 提示出租车到达的条件变量 pthread_cond_t taxiCond; / 同步锁 pthread_mutex_t taxi
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- linux 多线程编程 多线程 编程
![提示](https://www.taowenge.com/images/bang_tan.gif)
限制150内