Condition Variable使用及其Thread Cancellation线程取消

条件变量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 }
原文地址:https://www.cnblogs.com/NerdWill/p/5003570.html