线程条件量使用注意事项
pthread_cond_wait的使用:
pthread_mutex_t qlock; pthread_cond_t qready; /************pthread_cond_wait()的使用方法**********/ pthread_mutex_lock(&qlock); /*lock*/ //等待某资源,并以qready作为条件通知我们 while (condition == FALSE){ pthread_cond_wait(&qready, &qlock); /*block-->unlock-->wait() return-->lock*/ } //do something pthread_mutex_unlock(&qlock); /*unlock*/ /*****************************************************/
使用while循环来判断条件是否成立的原因:pthread_cond_signal在多处理器上可能同时唤醒多个线程,当你只能让一个线程处理某个任务时,其它被唤醒的线程就需要继续 wait, while循环的意义就体现在这里了,而且规范要求pthread_cond_signal至少唤醒一个pthread_cond_wait上的线程,其实有些实现为了简单在单处理器上也会唤醒多个线程. 某些应用,如线程池,pthread_cond_broadcast唤醒全部线程,但我们通常只需要一部分线程去做执行任务,所以其它的线程需要继续wait.所以强烈推荐此处使用while循环. (惊群效应)
pthread_cond_signal唤醒信号可能丢失:pthread_cond_signal函数的作用是发送一个信号给另外一个正在处于阻塞等待状态的线程,使其脱离阻塞状态,继续执行.如果没有线程处在阻塞等待状态, pthread_cond_signal也会成功返回,在这种情况下,该唤醒信号丢失。所以,如果程序是严格依赖pthread_cond_signal来做同步的,必须保证该条件量已经处于阻塞wait状态。以下是一个唤醒信号丢失的例子:
Thread A:
pthread_mutex_lock(&mutex); while (condition == FALSE) pthread_cond_wait(&cond, &mutex); pthread_mutex_unlock(&mutex);
Thread B:
condition = TRUE;
pthread_cond_signal(&cond);
那么可能出现这样的情况:
thread A thread B pthread_mutex_lock(&mutex); while (condition == FALSE) condition = TRUE; pthread_cond_signal(&cond); pthread_cond_wait(&cond, &mutex);
pthread_cond_signal的使用:
第一种:
pthread_mutex_lock
......
pthread_cond_signal
pthread_mutex_unlock
缺点:在某下线程的实现中,会造成等待线程从内核中唤醒(由于cond_signal)然后又回到内核空间(因为cond_wait返回后会有原子加锁的行为),所以一来一回会有性能的问题。但是在LinuxThreads或者NPTL里面,就不会有这个问题,因为在Linux 线程中,有两个队列,分别是cond_wait队列和mutex_lock队列, cond_signal只是让线程从cond_wait队列移到mutex_lock队列,而不用返回到用户空间,不会有性能的损耗。所以在Linux中推荐使用这种模式。
第二种:
pthread_mutex_lock
......
pthread_mutex_unlock
pthread_cond_signal
优点:不会出现之前说的那个潜在的性能损耗,因为在signal之前就已经释放锁了
缺点:如果unlock和signal之前,有个低优先级的线程正在mutex上等待的话,那么这个低优先级的线程就会抢占高优先级的线程(cond_wait的线程),而这在上面的放中间的模式下是不会出现的。
所以,在Linux下最好pthread_cond_signal放中间,但从编程规则上说,其他两种都可以。
参考: