pthread_cleanup_push/pthread_cleanup_pop:
pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut); //可以注册pthread_mutex_unlock,也可以注册自定义的函数
pthread_mutex_lock(&mut);
//do something。此过程中假如本线程做某些事时异常退出,或者被别的线程cancel,那么mut就永远得不到执行
pthread_mutex_unlock(&mut);
pthread_cleanup_pop(0);
pthread_cond_wait(&cond, &mut):
内部顺序执行pthread_mutex_unlock(&mut),pthread_cond_just_wait(&cond),pthread_mutex_lock(&mut),其中,前两个函数(unlock和just_wait)必须从语义上原子化。如果不原子化,会出现unlock之后别的线程获得mut,然后发送signal/broadcast,最后本线程调用just_wait。也就是说just_wait发生在signal/broadcast之前,所以本线程永远不会得到唤醒。
对于同一个cond,必须用同一个mut来配合使用。
使用示例如下:
pthread_mutex_lock(&mut);
while(flag!=true) //如果flag不为true,我们调cond_wait把自己给阻塞了
pthread_cond_wait(&cond,&mut); //前后必须要加互斥锁,而pthread_cond_signal前后则无所谓加不加互斥锁
pthread_mutex_unlock(&mut);
pthread_cond_wait()前后必须加互斥锁,是为了保证对条件flag的互斥访问,如果不加互斥锁,可能出现如下情况:
thread1: thread2:
while(flag!=true) //flag==false
flag=true; //flag==true
pthread_cond_wait(); //thread1已进入阻塞状态,但其实此时flag是为true的,即漏过了这个条件了
..........
1、进入wait,处理条件变量,
2、解锁mut;
3、把自己给阻塞了;
4、睡眠;
5、睡眠;
6、。。。
7、收到别的线程通知(pthread_cond_signal/broadcast)可以醒了;
8、醒来;
9、尝试锁定mut,如果成功则函数返回;
10、不成功的话阻塞并等待mut可用。
以上步骤,可以由下图(来自pthread条件变量condition(配合mutex锁使用),经典,有图)描述:
此外,注意如果有多个线程在等待条件变量时,需要用while(flag!=true),在wait返回的时候再判断一次flag。原因是wait执行时可能存在下面的场景(signal/broadcast惊群,线程1和线程3同时收到信号):
线程1 线程3
1、收到别的线程通知(pthread_cond_signal/broadcast)可以醒了; 1、收到别的线程通知(pthread_cond_signal/broadcast)可以醒了;
2、尝试加锁mut失败; 2、成功锁定mut;
3、睡眠 3、置flag为false;
4、睡眠 4、解锁mut;
5、成功锁定mut;
6、wait函数返回,线程醒来。
线程1醒来后必须再判断flag,flag可能为false了,因为线程1加锁mut失败的时候flag被别的线程修改了。
pthread_cond_signal():
有两种用法,都可以:
用法1: 用法2:
pthread_mutex_lock(&mut); pthread_mutex_lock(&mut);
atomic_i++; atomic_i++;
pthread_cond_signal(&cond); pthread_mutex_unlock(&mut);
pthread_mutex_unlock(&mut); pthread_cond_signal(&cond);
两种用法各有优缺点:
用法1在某些OS的实现中,可能会造成signal之后还没unlock,但是另一个收到cond的线程在cond_wait()中最后试图lock,lock失败,导致重新陷入内核态,直到本线程unlock,由此带来性能损失。
用法2会出现unlock之后signal之前有别的低优先级线程抢占了mut,导致更高优先级的等待cond_wait的线程被低优先级线程抢占。
用法1在Linux下不会有上面提到的缺点,因为在Linux中,cond_signal只会让线程从cond_wait队列移到mutex_lock队列。