网上有些文章说,先singal再unlock,有可能会出现一种情况是被singal唤醒的线程会因为不能马上拿到mutex(还没被释放),从而会再次休眠,这样影响了效率。从而会有一个叫“wait morphing”优化,就是如果线程被唤醒但是不能获取到mutex,则线程被转移(morphing)到mutex的等待队列里。
但是我查看了下glibc的源代码,貌似没有发现有这种“wait morphing”优化。
man文档里提到:
The pthread_cond_broadcast() or pthread_cond_signal() functions may be called by a thread whether or not it currently owns the mutex that threads calling pthread_cond_wait() or pthread_cond_timedwait() have associated with the condition variable during their waits; however, if predictable scheduling behavior is required, then that mutex shall be locked by the thread calling pthread_cond_broadcast() or pthread_cond_signal().
可见在调用singal之前,可以不持有mutex,除非是“predictable scheduling”,可预测的调度行为。这种可能是实时系统才有这种严格的要求。
为什么要用while循环来判断条件是否成立?
while (workq == NULL)
pthread_cond_wait(&qready, &qlock);
而不用if来判断?
if (workq == NULL)
pthread_cond_wait(&qready, &qlock);
一个原因是spurious wakeup,但即使没有spurious wakeup,也是要用While来判断的。
比如线程A,线程B在pthread_cond_wait函数中等待,然后线程C把消息放到队列里,再调用pthread_cond_broadcast,然后线程A先获取到mutex,处理完消息完后,这时workq就变成NULL了。这时线程B才获取到mutex,那么这时实际上是没有资源供线程B使用的。所以从pthread_cond_wait函数返回之后,还是要判断条件是否成功,如果成立,再进行处理。
pthread_cond_signal和pthread_cond_broadcast
在这篇文章里,http://www.cppblog.com/Solstice/archive/2013/09/09/203094.html
给出的示例代码7里,认为调用pthread_cond_broadcast来唤醒所有的线程是比较好的写法。但是我认为pthread_cond_signal和pthread_cond_broadcast是两个不同东东,不能简单合并在同一个函数调用。只唤醒一个效率和唤醒全部等待线程的效率显然不能等同。典型的condition是用CLH或者MCS来实现的,要通知所有的线程,则要历遍链表,显然效率降低。另外,C++11里的condition_variable也提供了notify_one函数。
http://en.cppreference.com/w/cpp/thread/condition_variable/notify_one
mutex,condition是不是公平(fair)的?
这个在参考文档里没有说明,在网上找了些资料,也没有什么明确的答案。
我写了个代码测试,发现mutex是公平的。condition的测试结果也是差不多。
#include
#include
#include
#include
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; volatile int mutexCount = 0; void mutexFairTest(){ int localCount = 0; while(1){ pthread_mutex_lock(&lock); __sync_fetch_and_add(&mutexCount, 1); localCount += 1; if(mutexCount > 100000000){ break; } pthread_mutex_unlock(&lock); } pthread_mutex_unlock(&lock); printf("localCount:%d\n", localCount); } int main() { pthread_mutex_lock(&lock); pthread_create(new pthread_t, NULL, (void * (*)(void *))&mutexFairTest, NULL); pthread_create(new pthread_t, NULL, (void * (*)(void *))&mutexFairTest, NULL); pthread_create(new pthread_t, NULL, (void * (*)(void *))&mutexFairTest, NULL); pthread_create(new pthread_t, NULL, (void * (*)(void *))&mutexFairTest, NULL); pthread_create(new pthread_t, NULL, (void * (*)(void *))&mutexFairTest, NULL); pthread_create(new pthread_t, NULL, (void * (*)(void *))&mutexFairTest, NULL); pthread_mutex_unlock(&lock); sleep(100); }
输出结果是:
localCount:16930422
localCount:16525616
localCount:16850294
localCount:16129844
localCount:17329693
localCount:16234137
还特意在一个单CPU的
虚拟机上测试了下。输出的结果差不多。操作系统是ububtu14.04。
参考:
http://en.wikipedia.org/wiki/Spurious_wakeup
http://siwind.iteye.com/blog/1469216
http://www.cppblog.com/Solstice/archive/2013/09/09/203094.html
http://www.cs.cmu.edu/afs/cs/academic/class/15492-f07/www/pthreads.html