《多核程序设计课件4-Linux多线程编程.ppt》由会员分享,可在线阅读,更多相关《多核程序设计课件4-Linux多线程编程.ppt(56页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第五章第五章 Linux 多线程编程多线程编程浙江大学计算机学院POSIX标准标准POSIX的诞生和的诞生和Unix的发展密不可分的发展密不可分l各厂家对各厂家对Unix的开发各自为政,造成了的开发各自为政,造成了Unix的版本相的版本相当混乱,给软件的可移植性带来很大困难,对当混乱,给软件的可移植性带来很大困难,对Unix的的发展极为不利发展极为不利POSIXl可移植操作系统接口:可移植操作系统接口:Portable Operating System Interfacel电气和电子工程师协会(电气和电子工程师协会(Institute of Electrical and Electronics
2、 Engineers,IEEE)开发)开发l提高提高 UNIX 环境下应用程序的可移植性环境下应用程序的可移植性许多其它的操作系统,例如许多其它的操作系统,例如 Microsoft Windows NT,都支持,都支持 POSIX 标准标准 POSIX 线程库线程库Pthreads介绍介绍IEEE POSIX IEEE POSIX 标准标准 p1003.1c(Pthreads)p1003.1c(Pthreads)定义了处理线程的一系列定义了处理线程的一系列C C 语语言类型的言类型的APIAPI。lPOSIX POSIX 线程线程 是是 线程的线程的 POSIXPOSIX标准,定义了创建和操纵
3、线程的一套标准,定义了创建和操纵线程的一套 APIAPI在在LinuxLinux中,线程一般被认为是中,线程一般被认为是“轻量级的进程轻量级的进程”。Linux Linux 创建进程所使用的函数是创建进程所使用的函数是fork()fork()或者或者vforkvfork()()。而对线程的创。而对线程的创建和管理,建和管理,LinuxLinux可以使用可以使用POSIXPOSIX的线程库的线程库pthreadspthreads提供的提供的APIsAPIs。LinuxLinux提供的多线程和多进程执行环境主要目的是提高系统资源利用提供的多线程和多进程执行环境主要目的是提高系统资源利用率和任务的并
4、发或并行程度。率和任务的并发或并行程度。针对针对WindowsWindows操作系统,操作系统,PthreadsPthreads也存在一个开放源代码的版本,称也存在一个开放源代码的版本,称为为pthreads-win32pthreads-win32 POSIX pthreads库库线程的创建线程的创建POSIX POSIX pthreadspthreads 线程库中提供的创建线程的函数是线程库中提供的创建线程的函数是pthread_createpthread_create()(),函数原型是:,函数原型是:int pthread_create(pthread_t *thread,pthread
5、_attr_t*attr,void*(*start_routine)(void*),void*arg);第一个参数是第一个参数是pthread_tpthread_t 类型的指针,这个指针指向用来存类型的指针,这个指针指向用来存放当线程创建成功后的所创建的线程的标志放当线程创建成功后的所创建的线程的标志 第二个参数表明被创建的线程可以拥有的属性第二个参数表明被创建的线程可以拥有的属性 第三个参数是一函数指针,此函数指针指向线程的实现函数第三个参数是一函数指针,此函数指针指向线程的实现函数第四个参数第四个参数argarg是是void*void*类型的,此参数指向实际线程处理类型的,此参数指向实际线
6、程处理函数执行的时候所需要的参数函数执行的时候所需要的参数 POSIX pthreads库库(续续)线程的退出线程的退出 在线程的处理函数中,可以显式的调用在线程的处理函数中,可以显式的调用pthread_exitpthread_exit()()结束线结束线程执行。程执行。pthread_exitpthread_exit()()函数的函数原型是:函数的函数原型是:void pthread_exit(void*retval);参数是指向线程的返回值参数是指向线程的返回值 线程的退出不能简单使用线程的退出不能简单使用exit()exit()函数,因为一旦使用了函数,因为一旦使用了 exitexit
7、()()函数,实际上是整个进程的退出,会导致其他线程也随着进函数,实际上是整个进程的退出,会导致其他线程也随着进程的消亡而消亡程的消亡而消亡POSIX pthreads库库(续续)等待线程结束等待线程结束 线程创建完毕后,创建线程的线程,就可以使用线程创建完毕后,创建线程的线程,就可以使用pthread_joinpthread_join()()函数等待被创建的线程的结束。函数等待被创建的线程的结束。pthread_joinpthread_join()()函数会挂起创建线程的线程的执行,直到等待函数会挂起创建线程的线程的执行,直到等待到想要等待的子线程。到想要等待的子线程。pthread_joi
8、npthread_join()()函数的函数原型是:函数的函数原型是:int pthread_join(pthread_t th,void*thread_return);第一个参数第一个参数thth是需要等待的线程的标志是需要等待的线程的标志 如果如果thread_returnthread_return不为空,那么不为空,那么thread_returnthread_return指向指向thth返回返回的值的值 调用调用pthread_joinpthread_join()()函数的目的是释放相关内存资源函数的目的是释放相关内存资源POSIX pthreads库库(续续)线程的分离线程的分离 pt
9、hread_joinpthread_join()()函数虽然可以等待被创建的线程的结束,且函数虽然可以等待被创建的线程的结束,且可以回收被创建的线程的相关内存资源,但是这个函数的主要可以回收被创建的线程的相关内存资源,但是这个函数的主要缺点是要挂起调用缺点是要挂起调用pthread_joinpthread_join()()的线程。的线程。POSIXPOSIX线程库提供了一个函数线程库提供了一个函数pthread_detachpthread_detach()(),使得子线程,使得子线程本身自己有自我回收内存资源的能力。本身自己有自我回收内存资源的能力。此函数的原型是:此函数的原型是:int pt
10、hread_detach(pthread_t th);这个函数的目的是让线程这个函数的目的是让线程 thth 可以处于分离可以处于分离(detached)(detached)状态状态 处于分离状态的线程有能力在自己结束执行的时候回收相关处于分离状态的线程有能力在自己结束执行的时候回收相关的内存资源的内存资源 POSIX pthreads库库(续续)获得当前线程标志获得当前线程标志 使用使用pthread_selfpthread_self()()函数可以获得当前线程的标志,函数可以获得当前线程的标志,pthread_selfpthread_self()()的返回值就是当前线程的标志。其函数原型是
11、:的返回值就是当前线程的标志。其函数原型是:lpthread_t pthread_self(void);线程的撤销线程的撤销一个线程可以通过向另个线程发送一个线程可以通过向另个线程发送“请求请求”来结束另一个线程来结束另一个线程的执行。的执行。pthread_cancelpthread_cancel()()函数可以完成这个功能。函数可以完成这个功能。接收撤销请求的线程并不是接收撤销请求的线程并不是“随便随便”就结束了自己的执行,它就结束了自己的执行,它可以忽略、推迟、或者立即响应别的线程发来的结束线程执行可以忽略、推迟、或者立即响应别的线程发来的结束线程执行的请求,这取决于线程设置。的请求,这
12、取决于线程设置。这里的这里的“推迟推迟”是指线程执行到撤销点是指线程执行到撤销点(cancellation point)(cancellation point)的时候,才执行线程的撤销操作。的时候,才执行线程的撤销操作。POSIX pthreadsPOSIX pthreads库中关于撤销操作的函数有:库中关于撤销操作的函数有:lint pthread_setcancelstate(int state,int*oldstate);lint pthread_setcanceltype(int type,int*oldtype);lvoid pthread_testcancel(void);线程的撤
13、销线程的撤销(续续)使用线程撤销相关的操作的例子使用线程撤销相关的操作的例子#include#include#include#include#define THREAD_NUMBER 2static pthread_cond_t cond=PTHREAD_COND_INITIALIZER;static pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;pthread_t ptTHREAD_NUMBER;void*thread1(void*arg)pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
14、pthread_mutex_lock(&mutex);sleep(5);printf(now thread1 is in cancelation pointn);/*pthread_cond_wait 是一撤销点,是一撤销点,thread1 在这里等待条件变量的满足在这里等待条件变量的满足*/pthread_cond_wait(&cond,&mutex);pthread_mutex_unlock(&mutex);pthread_exit(NULL);线程的撤销线程的撤销(续续)lvoid*thread2(void*arg)ll int i=0;l printf(thread2 sends ca
15、ncelation request to thread1n);l /*向线程向线程 thread1 发送撤销请求发送撤销请求*/l pthread_cancel(pt0);l printf(thread2 endsn);l pthread_exit(NULL);llint main(int argc,char*argv)ll int i;l int ret_val;l ret_val=pthread_create(&pt0,NULL,thread1,NULL);l if(ret_val!=0)l printf(pthread_create error!n);l exit(1);l l ret_
16、val=pthread_create(&pt1,NULL,thread2,NULL);l if(ret_val!=0)l printf(pthread_create error!n);l exit(1);l 线程的撤销线程的撤销(续续)lfor(i=0;i THREAD_NUMBER;i+)l ret_val=pthread_join(pti,NULL);l if(ret_val!=0)l printf(pthread_join error!n);l exit(1);l l l pthread_mutex_destroy(&mutex);l pthread_cond_destroy(&cond
17、);l return 0;l 程序运行结果:程序运行结果:lthread2 sends cancelation request to thread1lthread2 endslnow thread1 is in cancelation point在撤销线程的时候,可以编写程序让线程进一步进行所谓的在撤销线程的时候,可以编写程序让线程进一步进行所谓的“清理清理”工作,比如已经拥有了某个工作,比如已经拥有了某个 mutexmutex,在清理例程中可以,在清理例程中可以释放这个释放这个 mutexmutex;如果动态分配了内存,那么可以在清理例程;如果动态分配了内存,那么可以在清理例程中释放动态分配
18、的内存。中释放动态分配的内存。使用使用Pthreads编写的程序例子编写的程序例子一个简单的多线程程序一个简单的多线程程序helloworld.chelloworld.c,其创建了两个几乎一样其创建了两个几乎一样的线程的线程l#include l#include l#include l#include l#define THREAD_NUMBER 2lint retval_hello1=2,retval_hello2=3;lvoid*hello1(void*arg)ll char*hello_str=(char*)arg;l sleep(1);l printf(%sn,hello_str);l
19、 pthread_exit(&retval_hello1);llvoid*hello2(void*arg)ll char*hello_str=(char*)arg;l sleep(2);l printf(%sn,hello_str);l pthread_exit(&retval_hello2);l 使用使用Pthreads编写的程序例子编写的程序例子(续续)int main(int argc,char*argv)int i;int ret_val;int*retval_hello2;/*申明申明pthread_t 类型的数组类型的数组 pt 用来存放创建线程得到的线程的标志。这里创建的两个线程
20、,分别传递了不同的参用来存放创建线程得到的线程的标志。这里创建的两个线程,分别传递了不同的参数,分别数,分别arg0 和和 arg1 指向所要传递的字符串起始地址。指向所要传递的字符串起始地址。*/pthread_t ptTHREAD_NUMBER;const char*argTHREAD_NUMBER;arg0=hello world from thread1;arg1=hello world from thread2;printf(Begin to create threads.n);/*使用使用 pthread_create()分别创建了两个线程。创建线程的时候,分别创建了两个线程。创建
21、线程的时候,pthread_create()的第二个参数是的第二个参数是 NULL,表示被创建的线程拥有缺省的属性:被创建的线程是处于可加入状态,且其调度机制是普通的非实时的,表示被创建的线程拥有缺省的属性:被创建的线程是处于可加入状态,且其调度机制是普通的非实时的*/ret_val=pthread_create(&pt0,NULL,hello1,(void*)arg0);if(ret_val!=0)printf(pthread_create error!n);exit(1);ret_val=pthread_create(&pt1,NULL,hello2,(void*)arg1);if(ret
22、_val!=0)printf(pthread_create error!n);exit(1);使用使用Pthreads编写的程序例子编写的程序例子(续续)printf(Now,the main thread returns.n);printf(Begin to wait for threads.n);/*主线程使用主线程使用 pthread_join()等待两个子线程的结束。其中,等待两个子线程的结束。其中,retval_hello0 和和 retval_hello1 分别指向两个线程通过调用分别指向两个线程通过调用 pthread_exit()返回的值。返回的值。*/for(i=0;i TH
23、READ_NUMBER;i+)ret_val=pthread_join(pti,(void*)&retval_helloi);if(ret_val!=0)printf(pthread_join error!n);exit(1);else printf(return value is%dn,*retval_helloi);return 0;在在linuxlinux 中,编译线程相关的程序的时候需要用到中,编译线程相关的程序的时候需要用到libpthreadlibpthread 库。比如要编译库。比如要编译helloworld.chelloworld.c 为可执行程序为可执行程序 hellowor
24、ldhelloworld,那,那么可以这样使用么可以这样使用 gccgcc 来编译:来编译:l#gcc helloworld.c-o helloworld lpthread 线程的属性线程的属性pthread_createpthread_create()()创建线程的时候,如果第二个参数是创建线程的时候,如果第二个参数是NULL NULL 那么使用那么使用缺省的线程属性。线程的属性名和其含义可以在下表中看到缺省的线程属性。线程的属性名和其含义可以在下表中看到v属性名属性名v意意义义v detachstatev选择被创建的线程是处于可加入的状态还是分离状态。可加入状态值是PTHREAD_CREA
25、TE_JOINABLE;分离状态值是PTHREAD_CREATE_DETACHED。缺省状态值是PTHREAD_CREATE_JOINABLE。pthread_attr_setdetachstate()可设置线程为加入或者分离状态;pthread_attr_getdetachstate()可以获得当前线程是否是加入的或者是分离的状态。v schedpolicyv为被创建的线程选择调度策略。被创建的线程的状态可以是SCHED_OTHER(一般的,非实时调度)、SCHED_RR(实时,轮转调度)或者SCHED_FIFO(实时,先进先出调度)。缺省值是SCHED_OTHER。实时调度SCHED_RR
26、 和 SCHED_FIFO 只能用于有超级用户权限的进程使用。pthread_attr_setschedpolicy()和 pthread_attr_getschedpolicy()函数可以设置和获得线程的调度属性。v schedparamv为被创建的线程选择调度参数。这里的调度参数指的是线程的调度优先级。缺省优先级是 0。这个属性对于 SCHED_OTHER 是不重要的;它只对SCHED_RR 和 SCHED_FIFO 两个和实时调度相关的调度方式有效。pthread_attr_setschedparam()和 pthread_attr_getschedparam()两个函数可以分别对线程的
27、优先级进行设置和获取。(注释:struct sched_param 在linux中为:struct sched_param int _sched_priority;)v inheritschedv选择对新创建的线程的调度策略和调度参数是否被schedpolicy 和schedparam 属性决定(这时的值是PTHREAD_EXPLICIT_SCHED)或者是通过父线程继承而得到的(这时的值是PTHREAD_INHERIT_SCHED)。缺省的值是PTHREAD_EXPLICIT_SCHED。v scopev为选择被创建的线程调度竞争范围。缺省值是PTHREAD_SCOPE_SYSTEM,表示线
28、程和系统的所有的其他运行在CPU上的进程争夺CPU 资源。如果是PTHREAD_SCOPE_PROCESS,表示调度的竞争只发生在运行于同一进程空间的线程之间,线程的优先级只在同一进程空间的线程之间有效,和其他进程无关。使用使用pthreads库创建线程的特点库创建线程的特点线程可使用存在于进程中的资源,因此创线程可使用存在于进程中的资源,因此创建线程比创建进程更快。建线程比创建进程更快。线程间的通信方式更容易,比如通过进程线程间的通信方式更容易,比如通过进程中的变量,可以让多个线程共享数据。中的变量,可以让多个线程共享数据。操作系统对线程的切换比对进程的切换更操作系统对线程的切换比对进程的切
29、换更容易和快速容易和快速线程互斥和同步线程互斥和同步Mutexmutexmutex可以用来保护并发读写操作中的共享的数据结构,实际上用可以用来保护并发读写操作中的共享的数据结构,实际上用mutexmutex可以用来实现临界代码区。对于可以用来实现临界代码区。对于mutexmutex有如下特性:有如下特性:l原子性。对原子性。对mutexmutex的加锁和解锁操作是原子的,一个线程进行的加锁和解锁操作是原子的,一个线程进行 mutex mutex 操操作的过程中,其他线程不能对同一个作的过程中,其他线程不能对同一个 mutex mutex 进行其他操作。进行其他操作。l单一性。拥有单一性。拥有m
30、utexmutex的线程除非释放的线程除非释放mutexmutex,否则其他线程不能拥有此,否则其他线程不能拥有此mutexmutex。l非忙等待。等待非忙等待。等待mutexmutex的线程处于等待状态,直到要等待的的线程处于等待状态,直到要等待的mutexmutex处于未处于未加锁状态,这时操作系统负责唤醒等待此加锁状态,这时操作系统负责唤醒等待此mutexmutex的线程。的线程。mutexmutex本身只能有两种可能的状态:锁定或未锁定本身只能有两种可能的状态:锁定或未锁定l当互斥量处于已加锁状态时,其所保护的代码段是不可访问的当互斥量处于已加锁状态时,其所保护的代码段是不可访问的l在
31、使用在使用mutexmutex的时候,首先必须初始化的时候,首先必须初始化mutexmutex。在使用。在使用mutexmutex的时候,如果的时候,如果程序编写不当,可能会出现程序编写不当,可能会出现“死锁死锁”现象现象线程互斥和同步线程互斥和同步Mutex(续续)在在POSIX POSIX 线程库中,存在三线程库中,存在三种种类型的类型的mutexmutex,分别是快速,分别是快速(fast)(fast)mutexmutex、递归、递归(recursive)mutex(recursive)mutex和错误检测和错误检测(error(error checking)mutexchecking)
32、mutex。l快速快速mutexmutex:如果有一个线程锁定了:如果有一个线程锁定了mutexmutex,那么其他线程如果想,那么其他线程如果想要获得此要获得此mutexmutex,必须等待,必须等待mutexmutex处于未锁定状态处于未锁定状态l递归递归mutexmutex:已经拥有此:已经拥有此mutexmutex的线程可执行多次加锁操作,且不的线程可执行多次加锁操作,且不必等待必等待mutexmutex处于未锁状态,但是对于其他线程,要想获得此处于未锁状态,但是对于其他线程,要想获得此mutexmutex,必须等待当此,必须等待当此mutexmutex 处于未锁定状态处于未锁定状态拥
33、有递归拥有递归mutexmutex的线程加锁的次数应该和解锁的次数相同的线程加锁的次数应该和解锁的次数相同l错误检测错误检测mutexmutex:如果错误检测:如果错误检测mutexmutex已经被一个线程锁定,那么已经被一个线程锁定,那么其他线程想要锁定这个其他线程想要锁定这个mutexmutex,使用,使用pthread_mutex_lockpthread_mutex_lock()()函数函数将返回将返回EDEADLKEDEADLK线程互斥和同步线程互斥和同步Mutex(续续)POSIX POSIX 线程库对线程库对mutexmutex提供了以下函数进行操作:提供了以下函数进行操作:l i
34、nt pthread_mutex_init(pthread_mutex_t*mutex,const pthread_mutexattr_t*mutexattr);l int pthread_mutex_lock(pthread_mutex_t*mutex);l int pthread_mutex_trylock(pthread_mutex_t*mutex);l int pthread_mutex_unlock(pthread_mutex_t*mutex);l int pthread_mutex_destroy(pthread_mutex_t*mutex);线程使用线程使用mutexmutex的
35、简单代码如下所示:的简单代码如下所示:l pthread_mutex_t mylock;l mylock=PTHREAD_MUTEX_INITIALIZER;l pthread_mutex_lock(&mylock);l /*do some exclusive operations*/l pthread_mutex_unlock(&mylock);线程互斥和同步线程互斥和同步Mutex(续续)pthread_mutex_init()用来初始化用来初始化mutex,并且使用,并且使用mutexattr参数来传递初始化参数来传递初始化mutex需要定义的属性。需要定义的属性。pthread_mut
36、ex_lock()用来获得用来获得mutexl如果当前线程想要获取的如果当前线程想要获取的mutex已经被其他线程锁定,且已经被其他线程锁定,且mutex是快速是快速mutex,那么调用,那么调用pthread_mutex_lock()将使得当前线程处于等待状将使得当前线程处于等待状态;态;l如果如果mutex是递归是递归mutex,那么,那么pthread_mutex_lock()立即返回,并立即返回,并记录本线程锁定此记录本线程锁定此mutex的次数,相同次数的的次数,相同次数的pthread_mutex_unlock()必须作用于此必须作用于此mutex,然后此,然后此mutex才能处于
37、未锁状态;才能处于未锁状态;l如果如果mutex是错误检测是错误检测mutex,如果,如果mutex已经处于锁定状态,其他线程已经处于锁定状态,其他线程尝试尝试pthread_mutex_lock()将立即返回将立即返回EDEADLK错误。错误。pthread_mutex_trylock()函数和函数和pthread_mutex_lock()函函数功能基本一致,只不过此函数是数功能基本一致,只不过此函数是“尝试尝试”获得获得mutex,如果不能获得,如果不能获得,其将立刻返回,并继续线程的执行其将立刻返回,并继续线程的执行pthread_mutex_unlock()函数用来释放函数用来释放mu
38、tex锁,以便供其他线锁,以便供其他线程使用。在使用完毕程使用。在使用完毕mutex后,应该使用后,应该使用pthread_mutex_destroy()函数来释放函数来释放mutex资源。资源。线程互斥和同步线程互斥和同步Mutex(续续)使用使用mutexmutex常见的错误是加锁和解锁不匹配或者位置不当。例如:常见的错误是加锁和解锁不匹配或者位置不当。例如:线程线程A A先使得先使得mutex1mutex1处于锁定状态,然后线程处于锁定状态,然后线程B B使得使得mutex2mutex2处于锁定状处于锁定状态。假设态。假设mutex1mutex1和和mutex2mutex2都是快速锁,那
39、么当线程都是快速锁,那么当线程A A要往要往mutex2mutex2上加上加锁的时候,线程锁的时候,线程A A此时只能等待。而线程此时只能等待。而线程B B也要获得也要获得mutex1mutex1,但是,但是mutex1mutex1已经处于锁定状态,且线程已经处于锁定状态,且线程A A由于在等待由于在等待mutex2mutex2解锁,故线程解锁,故线程B B也处于等待状态,这样一来,线程也处于等待状态,这样一来,线程A A和线程和线程B B都不能继续执行,造成了都不能继续执行,造成了所谓的所谓的“死锁死锁”。线程互斥和同步线程互斥和同步Mutex(续续)在同一线程中,线程在没有释放在同一线程中
40、,线程在没有释放mutex的情况下的情况下再次试图加锁再次试图加锁mutex在以上代码中,线程在获得在以上代码中,线程在获得mutex1后,使得后,使得mutex1处于加锁状态,然后调用函数处于加锁状态,然后调用函数f(x),此,此函数又在程序中使用函数又在程序中使用pthread_mutex_lock()函数试图加锁函数试图加锁mutex1,这样的结果是线程无,这样的结果是线程无法继续往下执行法继续往下执行pthread_mutex_lock(&mutex1);f(x);pthread_mutex_unlock(&mutex1);pthread_mutex_lock(&mutex1);pth
41、read_mutex_unlock(&mutex1);线程互斥和同步线程互斥和同步事件通信模型容易导致错误事件通信模型容易导致错误Pthreads模型没有提供与模型没有提供与Windows的的事件机制在概念上直接对应的功能事件机制在概念上直接对应的功能l条件变量条件变量l信号量信号量线程互斥和同步线程互斥和同步条件变量条件变量条件变量是线程的同步设备。在线程间使用条件变量可以使得一个线程在执条件变量是线程的同步设备。在线程间使用条件变量可以使得一个线程在执行过程中,因满足某个条件而发出信号通知另一个线程;而另一个线程可以行过程中,因满足某个条件而发出信号通知另一个线程;而另一个线程可以处于挂起
42、状态,等待某个条件的满足后,才继续执行。处于挂起状态,等待某个条件的满足后,才继续执行。l多用于存在一个或多个线程等待数据项的值发生改变的情况多用于存在一个或多个线程等待数据项的值发生改变的情况l线程不是线程不是“旋转旋转”而是阻塞在条件变量上,等待该条件变量被其他线程激发而是阻塞在条件变量上,等待该条件变量被其他线程激发l该激发信号通知这些等待线程数据项的值已经被修改,并使其开始或者恢复其处理该激发信号通知这些等待线程数据项的值已经被修改,并使其开始或者恢复其处理过程过程条件变量必须和条件变量必须和mutexmutex一起使用来避免竞争情况。一起使用来避免竞争情况。相关的操作函数如下:相关的
43、操作函数如下:lpthread_cond_t cond=PTHREAD_COND_INITIALIZER;lint pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t*cond_attr);lint pthread_cond_signal(pthread_cond_t*cond);lint pthread_cond_broadcast(pthread_cond_t*cond);lint pthread_cond_wait(pthread_cond_t*cond,pthread_mutex_t*mutex);lint pthread
44、_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t*mutex,const struct timespec*abstime);lint pthread_cond_destroy(pthread_cond_t*cond);线程互斥和同步线程互斥和同步条件变量条件变量pthread_cond_init()函数用来初始化条件变量函数用来初始化条件变量pthread_cond_signal()启动等待启动等待cond指向的条件指向的条件变量的一个线程变量的一个线程l如果没有线程等待条件变量,什么也不会发生;如果没有线程等待条件变量,什么也不会发生;
45、l如果有多个线程等待条件此条件变量,那么只有一个线程被如果有多个线程等待条件此条件变量,那么只有一个线程被重新启动执行,但是到底那个线程先启动执行,并没有指定重新启动执行,但是到底那个线程先启动执行,并没有指定pthread_cond_broadcast()函数启动所有的等待条函数启动所有的等待条件变量的线程件变量的线程pthread_cond_wait()原子性地解锁其第二个参数指原子性地解锁其第二个参数指向的向的mutex,然后等待条件变量条件的满足,然后等待条件变量条件的满足pthread_cond_timedwait()是在规定的时间内等待是在规定的时间内等待条件的满足条件的满足ptr
46、head_cond_wait()是无限制地等待是无限制地等待pthread_cond_destroy()释放条件变量所占的资源释放条件变量所占的资源线程互斥和同步线程互斥和同步条件变量条件变量(续续)使用条件变量的例子使用条件变量的例子threadcon.cthreadcon.c l#include l#include l#include l#include l#define THREAD_NUMBER 2l/*初始化条件变量初始化条件变量*/lstatic pthread_cond_t cond=PTHREAD_COND_INITIALIZER;l/*初始化初始化mutex*/lstatic
47、 pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;lvoid*thread1(void*arg)ll pthread_mutex_lock(&mutex);l printf(thread1 locked the mutexn);l printf(thread1 is waiting for condition signal.n);l pthread_cond_wait(&cond,&mutex);l printf(thread1 received condition signal!n);l pthread_mutex_unlock(&mutex)
48、;l printf(thread1 unlocked the mutexn);l pthread_exit(NULL);l线程互斥和同步线程互斥和同步条件变量条件变量(续续)lvoid*thread2(void*arg)ll int i=0;l struct timeval old,new;l gettimeofday(&old);l new=old;l pthread_mutex_lock(&mutex);l printf(thread2 locked the mutexn);l l /*休眠休眠 5 秒钟秒钟*/l while(new.tv_sec-old.tv_sec 5)l sleep
49、(1);l gettimeofday(&new);l i+;l printf(thread2 sleep%d secondsn,i);l l printf(thread1 calls pthread_cond_signal.n);l /*启动等待条件变量启动等待条件变量 cond 的其他线程的其他线程*/l pthread_cond_signal(&cond);l pthread_mutex_unlock(&mutex);l printf(thread2 unlocked the mutexn);l pthread_exit(NULL);l线程互斥和同步线程互斥和同步条件变量条件变量(续续)l
50、for(i=0;i THREAD_NUMBER;i+)l ret_val=pthread_join(pti,NULL);l if(ret_val!=0)l printf(pthread_join error!n);l exit(1);l l l return 0;l程序执行结果:程序执行结果:lthread1 locked the mutexlthread1 is waiting for condition signal.lthread2 locked the mutexlthread2 sleep 1 secondslthread2 sleep 2 secondslthread2 sleep