条件变量Condition Variable的一般用法:
唤醒用法:
1 struct { 2 pthread_mutex_t mutex; 3 pthread_cond_t cond; 4 //whatever variables maintain the condition 5 ) var = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, ... };//声明结构体并初始化 6 7 pthread_mutex_lock(&var.mutex); 8 //set condition true 9 pthread_cond_signal(&var.cond): 10 pthread_mutex_unlock(&var.mutex);
等待用法:
1 pthread_mutex_lock(&var.mutex); 2 while (/*condition is false*/) 3 pthread_cond_wait(&var.cond, &var.mutex); 4 //modify condition 5 pthread_mutex_unlock(&var.mutex);
避免锁冲突:
有一种情况是,唤醒线程中调用pthread_cond_signal之后,假如立即调度等待线程。那么等待线程立即运行然后停止,因为它不能获取到锁。为了不影响等待线程及时获取锁,唤醒线程另一种写法是:
1 int dosignal; 2 pthread_mutex_lock(&nready.mutex); 3 dosignal = (nready.nready == 0); 4 nready.nready++; 5 pthread_mutex_unlock(&nready.mutex); 6 7 //先释放锁,然后唤醒等待线程 8 if (dosignal) 9 pthread_cond_signal(&nready.cond);
即,先释放锁,然后唤醒。这样就避免了等待线程请求锁的冲突问题。而调用pthread_cond_wait之前必须加锁。
条件变量的线程取消(Thread Cancellation)问题:
在使用条件变量进行等待时,注意线程被取消时的锁释放问题。为了让线程退出时释放所持有的锁,可以设置pthread_cleanup_push清理函数,参数是清理函数及其参数,这些清理函数在线程被取消时或正常退出时(不管是pthread_exit还是从线程执行函数返回)都会被执行。使用pthread_cleanup_pop弹出清理函数栈顶的函数,参数非0表示执行,0表示不执行。
程序正常执行时,条件变量的wait函数正常返回,所以,pthread_cleanup_pop(0)表示,取消函数不会被执行;当程序在wait中被取消时,程序不会从wait函数返回,而是重新获取条件变量关联的锁之后,直接退出,但是退出之前调用清理函数。
一般用法:
1 pthread_mutex_lock(&var.mutex); 2 while (/*condition is false*/) 3 { 4 pthread_cleanup_push(/*cancel_handler*/,/*arg*/); 5 //pthread_cond_wait是取消点,被取消时,函数不会返回,但是会重新获取条件变量关联的锁,即var.mutex。因为该函数内部实现机制就是先释放锁然后等待,等待结束再原子操作重新获取锁。 6 pthread_cond_wait(&var.cond, &var.mutex); 7 pthread_cleanup_pop(0); 8 } 9 //modify condition 10 pthread_mutex_unlock(&var.mutex);
在清理函数中如cancel_handler,释放条件变量关联的锁即可。
1 void cancel_handler(void *arg) 2 { 3 var = arg; 4 //该函数将相关对象恢复至被cancel之前的状态 5 6 //其他操作 7 pthread_mutex_unlock(&var.mutex); 8 }