unix环境高级编程-条件变量
条件变量(Condtion Variable)是在多线程程序中用来实现“等待->唤醒”逻辑常用的方法。
举个实例场景: 一个进程p中有两个线程A和B。A运行到某处后,需要等到bool变量flag变为true后才能继续运行,而设置flag的值为true这个操作需要线程B来完成,这种情况我们如何来实现?
#include <pthread.h> int pthread_cond_init (pthread_cond_t *cond,const pthread_condattr_t *cond_attr) ; int pthread_cond_destroy (pthread_cond_t *cond); 两者的返回值都是:若成功则返回0,否则返回错误号 /* 等待条件变为真 */ int pthread_cond_wait (pthread_cond_t *cond,pthread_mutex_t *mutex); /* 限时等待条件为真 */ int pthread_cond_timedwait (pthread_cond_t *cond,pthread_mutex_t *mutex,const struct timespec *abstime);传递给pthread_cond_wait的互斥量对条件进行保护。调用者把锁住的互斥量传给函数,函数然后把调用线程放到等待条件的线程列表中,对互斥量解锁。pthread_cond_wait返回时,互斥量再次被锁住。
#include<pthread.h> int pthread_cond_signal(pthread_cond_t *cond); in pthread_cond_broadcast(pthread_cond_t *cond); 两个函数的返回值:若成功,返回0;否则,返回错误编号
pthread_cond_wait()用于阻塞当前线程,等待别的线程使用pthread_cond_signal()或pthread_cond_broadcast来唤醒它。pthread_cond_wait()必须与pthread_mutex 配套使用。
pthread_cond_wait()函数一进入wait状态就会自动release mutex。当其他线程通过pthread_cond_signal()或pthread_cond_broadcast,把该线程唤醒,使pthread_cond_wait()通过(返回)时,
该线程又自动获得该mutex。
pthread_cond_signal函数的作用是发送一个信号给另外一个正在处于阻塞等待状态的线程,使其脱离阻塞状态,继续执行.如果没有线程处在阻塞等待状态,pthread_cond_signal也会成功返回。
使用pthread_cond_signal一般不会有“惊群现象”产生,他最多只给一个线程发信号。假如有多个线程正在阻塞等待着这个条件变量的话,那 么是根据各等待线程优先级的高低确定哪个线程接收到信号开始继续执行。如果各线程优先级相同,则根据等待时间的长短来确定哪个线程获得信号。但无论如何一 个pthread_cond_signal调用最多发信一次。
但是pthread_cond_signal在多处理器上可能同时唤醒多个线程,当你只能让一个线程处理某个任务时,其它被唤醒的线程就需要继续 wait,而且规范要求pthread_cond_signal至少唤醒一个pthread_cond_wait上的线程,其实有些实现为了简单在单处理器上也会唤醒多个线程.
另外,某些应用,如线程池,pthread_cond_broadcast唤醒全部线程,但我们通常只需要一部分线程去做执行任务,所以其它的线程需要继续wait.所以强烈推荐对pthread_cond_wait()使用while循环来做条件判断.
以下代码摘自unix环境高级编程 #include <pthread.h> struct msg { struct msg *m_next; /* ... more stuff here ... */ }; struct msg *workq; pthread_cond_t qready = PTHREAD_COND_INITIALIZER; pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER; void process_msg(void) { struct msg *mp; for (;;) { pthread_mutex_lock(&qlock); while (workq == NULL) pthread_cond_wait(&qready,&qlock); mp = workq; workq = mp->m_next; pthread_mutex_unlock(&qlock); /* now process the message mp */ } } void enqueue_msg(struct msg *mp) { pthread_mutex_lock(&qlock); mp->m_next = workq; workq = mp; pthread_mutex_unlock(&qlock); pthread_cond_signal(&qready); }
为什么使用while而不是if while (...) pthread_cond_wait(&qready,&qlock); 1.假设仓库为空,有2个消费者在等待商品,设为C1和C2 2.假设生产者只生产了1件商品,然后调用pthread_cond_broadcast,则C1和C2都会得到通知 3.假设C1比C2先得到通知,然后加锁把商品消费了,并且解锁,这时C2就能拿到锁,但是此时商品已经没有了,如果此时C2不做检测,则会出现数据同步问题 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |