推荐的pthread_cond_wait()和pthread_cond_signal()使用方式:
pthread_mutex_lock(&m);
while( condition_is_false )
pthread_cond_wait(&cond, &m);
pthread_mutex_unlock(&m);
另一端一般是:
pthread_mutex_lock(&m); // pthread_cond_wait已自动释放锁
......
pthread_cond_signal(&v);
pthread_mutex_unlock(&m); // 释放锁,使得pthread_cond_wait可以自动再次获得锁
注意调用pthread_cond_wait()之前必须获得锁。pthread_cond_wait()其实对互斥量做了操作,首先,将解锁与挂起线程做为原子操作执行,这样pthread_cond_signal()即可获互斥量。当pthread_cond_wait()返回时,又会自动加锁,所以其效果相当于持有的锁的状态没有改变。
被pthread_cond_wait()阻塞的线程可以被pthread_cond_signal函数,pthread_cond_broadcast函数唤醒,也可能在被信号中断后被唤醒(造成假唤醒)。pthread_cond_wait()函数的返回并不意味着条件的值一定发生了变化(有可能是假唤醒),也可能是函数出错返回,因此必须重新检查条件的值,比如用while()来确认。pthread_cond_wait()函数返回时,相应的互斥锁将被当前线程锁定。
必须在互斥锁的保护下使用相应的条件变量。否则对条件变量的通知有可能发生在等待条件变量之前,从而造成死锁;导致死锁的最常见错误是自死锁或递归死锁。在自死锁或递归死锁中,线程尝试获取已被其持有的锁。递归死锁是在编程时很容易犯的错误。另外,如果没有线程被阻塞在条件变量上,那么调用pthread_cond_signal()将没有作用。
也可以用int pthread_cond_timedwait(),函数到了一定的时间,即使条件未发生也会解除阻塞(返回ETIMEDOUT)。函数返回时,相应的互斥锁往往是锁定的,即使是函数出错返回。
对于pthread_cond_broadcast(),不同的线程可以共用一个条件变量,但是锁还是要不同的,因为在wait()之前一定要获得锁;如果确认对锁没有造成死锁的竞争,pthread_cond_broadcast()的方式用一个锁也可以。
PS: 条件变量函数并不是异步信号安全的,因此不能在信号处理函数中调用。具体地说,在信号处理函数中调用 pthread_cond_signal() 或 pthread_cond_broadcast() 可能会导致调用线程的死锁。