互斥锁一个明显的缺点是它只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用。使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。一旦其他的某个线程改变了条件变量,它将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。这些线程将重新锁定互斥锁,并重新测试条件是否满足。
一般地,条件变量是利用线程间共享的全局变量进行同步的一种机制。某些线程可能守候着一个条件变量,直到某个其他的线程给这个条件变量发送一个信号(或通告),这时这些线程中的一个就会苏醒,处理这个事件。也有可能利用对条件变量的广播唤醒所有守候着这个条件变量的线程。条件变量不能提供锁定,它必须和一个互斥量同时使用,提供访问这个环境变量时必要的锁定。条件变量宏观上类似if语句,符合条件就能执行某段程序,否则只能等待条件成立。Linux也提供了一系列对条件变量操作的函数。对条件变量进行操作的函数见表10-4。
表10-4 对条件变量进行操作的函数
条件变量采用的数据类型是pthread_cond_t,在使用之前必须进行初始化。条件变量和互斥锁一样,也有静态和动态两种创建方式。静态方式使用PTHREAD_COND_INITIALIZER常量,具体如下:
动态方式调用pthread_cond_init()函数,其原型为
其中,cond是一个指向结构pthread_cond_t的指针;cond_attr是一个指向结构pthread_condattr_t的指针。结构pthread_condattr_t是条件变量的属性结构,和互斥锁一样可以用来设置条件变量是进程内可用还是进程间可用,默认值是PTHREAD_PROCESS_PRIVATE,即此条件变量被同一进程内的各个线程所使用。注意:初始化条件变量只有未被使用时才能重新初始化或被释放。
函数pthread_cond_wait()使线程阻塞在一个条件变量上。它的函数原型为
线程解开mutex指向的锁并被条件变量cond阻塞,直到条件被信号唤醒。
通常,条件表达式在互斥锁的保护下求值。如果条件表达式为假,线程就基于条件表达式阻塞。当一个线程改变条件变量值时,条件变量获得一个信号,使得等待条件变量的线程退出等待状态。
另一个用来阻塞线程的函数是pthread_cond_timedwait(),它的原型为
它比函数pthread_cond_wait()多了一个时间参数,经历abstime段时间后,即使条件变量不满足,阻塞也被解除。
线程可以被函数pthread_cond_signal()和函数pthread_cond_broadcast()唤醒。但是,条件变量只是起阻塞和唤醒线程的作用,具体的判断条件还需用户给出。线程被唤醒后,它将重新检查判断条件是否满足,如果还不满足,一般地线程应该仍阻塞在这里,等待被下一次唤醒。这个过程一般用while语句实现。函数pthread_cond_signal()的原型为
(www.xing528.com)
它用来释放被阻塞在条件变量cond上的一个线程。多个线程阻塞在此条件变量上时,哪一个线程被唤醒是由线程的调度策略所决定的。函数pthread_cond_broadcast()可激活所有的等待线程,其函数原型为
当一个条件变量不再使用时,需要将其清除。清除一个条件变量使用函数pthread_cond_destroy()来实现,其函数原型为
pthread_cond_destroy()函数用于清除由cond指向的条件变量。
只有在没有线程等待该条件变量时才能清除这个条件变量,否则返回EBUSY。
【例10-4】条件变量。
本例使用pthread_mutex_t()来实现条件变量。
设计步骤
1)在Vim中创建一个新工程文件,命名为“example10_4.c”。
2)在“example10_4.c”中创建的代码如下所示。
3)用GCC编译运行程序,结果如图10-4所示。
图10-4 例10-4的运行结果
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。