论条件变量cond_wait的原子性
2014-07-02 14:00
141 查看
使用的基本模板如下(参考APUE):
signal代码序列如下,
pthread_mutex_lock
...
pthread_cond_signal
pthread_mutex_unlock
wait代码序列如下,
while (1){
pthread_mutex_lock(&mutex);
while(iCount < 100){
pthread_cond_wait(&cond, &mutex);
}
printf("iCount >= 100\r\n");
iCount = 0;
pthread_mutex_unlock(&mutex);
}
小小几行代码,背后有大学问,这里就把几点重要的地方阐明一下,
首先,signal序列代码中,pthread_cond_signal和pthread_mutex_unlock可以对调,各有利弊参见APUE 11章习题4,以及百度百科词条(pthread_cond_signal),两种写法各有利弊,linux下变成推荐本文开头的写法。
其次,我们始终假定,signal会通知到 不止一个线程。这里会涉及到调度问题,不再详述。
最后,cond_wait是原子的。phtread_cond_wait 的实现可以理解为如下几个步骤:
1 unlock mutex
2 sleep & wait for cond
3 cond ok & return
4 unlock mutex
解锁1和睡眠2是原子的,加锁3和唤醒4是原子的. 原子就是指线程在执行相关步骤时,不会被切换出去。如果不原子会有什么问题呢?
1~2 解锁和睡眠是原子的:lock --> 检查变量不满足 --> unlock --> sleep;如果变量的改变以及通知事件发生在unlock和sleep中间,那么你不会检测到,也就是错过了这次通知.
3~4 加锁和唤醒是原子的:wakeup -- > lock ----> 检查变量是否满足条件:如果在wakeup之后,在lock之前,其他线程可以修改数据,导致我们Lock后检查的数据可能与我们被唤醒的通知不是一个通知,也就是被1号通知唤醒,却检查了2号通知对变量的改变。
也就是说,如果1~2之间wait线程切出去了,那么他将因此损失一次本来可能属于自己的唤醒条件。
你也许会问,SMP条件下,两个线程同时运行,发出signal的线程和wait线程同时进行,1~2之间还是会发生可满足条件导致miss啊?但是,要明白,这个miss事件不是wait线程自己切换造成的,况且,在下次while判断时候,会接到这个提醒——如果,没有同事wait的其他线程的改变。同理,如果3~4之间发生事件(也是第三方线程知识),使本来可满足的条件变为不满足,则下次while循环也能判断出来。
假如有多个线程都在wait,那么wait的线程之间会影响彼此的判断,但是,这就是你允许多个wait的必须前提啊?!这还有神马可解释的呢!
signal代码序列如下,
pthread_mutex_lock
...
pthread_cond_signal
pthread_mutex_unlock
wait代码序列如下,
while (1){
pthread_mutex_lock(&mutex);
while(iCount < 100){
pthread_cond_wait(&cond, &mutex);
}
printf("iCount >= 100\r\n");
iCount = 0;
pthread_mutex_unlock(&mutex);
}
小小几行代码,背后有大学问,这里就把几点重要的地方阐明一下,
首先,signal序列代码中,pthread_cond_signal和pthread_mutex_unlock可以对调,各有利弊参见APUE 11章习题4,以及百度百科词条(pthread_cond_signal),两种写法各有利弊,linux下变成推荐本文开头的写法。
其次,我们始终假定,signal会通知到 不止一个线程。这里会涉及到调度问题,不再详述。
最后,cond_wait是原子的。phtread_cond_wait 的实现可以理解为如下几个步骤:
1 unlock mutex
2 sleep & wait for cond
3 cond ok & return
4 unlock mutex
解锁1和睡眠2是原子的,加锁3和唤醒4是原子的. 原子就是指线程在执行相关步骤时,不会被切换出去。如果不原子会有什么问题呢?
1~2 解锁和睡眠是原子的:lock --> 检查变量不满足 --> unlock --> sleep;如果变量的改变以及通知事件发生在unlock和sleep中间,那么你不会检测到,也就是错过了这次通知.
3~4 加锁和唤醒是原子的:wakeup -- > lock ----> 检查变量是否满足条件:如果在wakeup之后,在lock之前,其他线程可以修改数据,导致我们Lock后检查的数据可能与我们被唤醒的通知不是一个通知,也就是被1号通知唤醒,却检查了2号通知对变量的改变。
也就是说,如果1~2之间wait线程切出去了,那么他将因此损失一次本来可能属于自己的唤醒条件。
你也许会问,SMP条件下,两个线程同时运行,发出signal的线程和wait线程同时进行,1~2之间还是会发生可满足条件导致miss啊?但是,要明白,这个miss事件不是wait线程自己切换造成的,况且,在下次while判断时候,会接到这个提醒——如果,没有同事wait的其他线程的改变。同理,如果3~4之间发生事件(也是第三方线程知识),使本来可满足的条件变为不满足,则下次while循环也能判断出来。
假如有多个线程都在wait,那么wait的线程之间会影响彼此的判断,但是,这就是你允许多个wait的必须前提啊?!这还有神马可解释的呢!
相关文章推荐
- 线程同步之条件变量:pthread_cond_signal和pthread_cond_wait
- 线程同步之条件变量:pthread_cond_signal和pthread_cond_wait
- 多线程机制(条件变量):pthread_cond_wait && pthread_cond_signal
- 线程同步之条件变量:pthread_cond_signal和pthread_cond_wait
- pthread_cond_wait理解以及互斥锁与条件变量使用的总结
- 线程中的条件变量:pthread_cond_wait()用法分析
- 基于条件变量阻塞pthread_cond_wait
- 条件锁(条件Mutex)pthread_cond_wait、pthread_cond_signal、pthread_cond_broadcast的使用
- pthread_cond_t和pthread_mutex_t(条件变量和互斥锁)
- 多线程的pthread_cond_wait后,记住再次检测条件
- 线程条件锁 pthread_cond_wait()/pthread_cond_signal()
- 多线程编程:条件变量pthread_cond_t
- 转:条件变量、pthread_cond_init
- pthread_cond_wait和pthread_cond_signal以及互斥变量的使用情况
- 初始化条件变量pthread_cond_init
- 条件锁(条件Mutex)pthread_cond_wait、pthread_cond_signal、pthread_cond_broadcast的使用[转]
- 多线程的pthread_cond_wait后,记住再次检测条件
- Linux的锁和条件变量用法 | pthread_mutex_lock | pthread_cond_signal
- Linux的锁和条件变量用法 | pthread_mutex_lock | pthread_cond_signal
- 条件锁(条件Mutex)pthread_cond_wait、pthread_cond_signal、pthread_cond_broadcast的使用