为什么phread_cond_wait要加while?

江东橘子 2011-07-28 05:00:05
说加while的目的是只让一个线程唤醒,其他的都等待

下面这段绿色的是小弟从网上拷贝而来的,看了一下,还是有个地方不明白:
pthread_mutex_lock(&mut);
while (x <= y) {
pthread_cond_wait(&cond, &mut);
}
/* operate on x and y */
pthread_mutex_unlock(&mut);
和: pthread_mutex_lock(&mut);
/* modify x and y */
if (x > y) pthread_cond_signal(&cond);
pthread_mutex_unlock(&mut);
其实函数的执行过程非常简单,在第一个线程执行到pthread_cond_wait(&cond,&mut)时,此时如果X<=Y,则此函数就将mut互斥量解锁,再将cond条件变量加锁,此时第一个线程挂起(不占用任何CPU周期)。

而在第二个线程中,本来因为mut被第一个线程锁住而阻塞,此时因为mut已经释放,所以可以获得锁mut,并且进行修改X和Y的值,在修改之后,一个IF语句判定是不是X>Y,如果是,则此时pthread_cond_signal()函数会唤醒第一个线程,并在下一句中释放互斥量mut。然后第一个线程开始从pthread_cond_wait()执行,首先要再次锁mut,如果锁成功,再进行条件的判断(至于为什么用WHILE,即在被唤醒之后还要再判断,后面有原因分析),如果满足条件,则被唤醒进行处理,最后释放互斥量mut。

至于为什么在被唤醒之后还要再次进行条件判断(即为什么要使用while循环来判断条件),是因为可能有“惊群效应”。有人觉得此处既然是被唤醒的,肯定是满足条件了,其实不然。如果是多个线程都在等待这个条件,而同时只能有一个线程进行处理,此时就必须要再次条件判断,以使只有一个线程进入临界区处理。

thread_cond_signal在多处理器上可能同时唤醒多个线程,当你只能让一个线程处理某个任务时,其它被唤醒的线程就需要继续 wait,while循环的意义就体现在这里了,而且规范要求pthread_cond_signal至少唤醒一个pthread_cond_wait上的线程,其实有些实现为了简单在单处理器上也会唤醒多个线程.
2,某些应用,如线程池,pthread_cond_broadcast唤醒全部线程,但我们通常只需要一部分
线程去做执行任务,所以其它的线程需要继续wait.所以强烈推荐此处使用while循环.

其实说白了很简单,就是pthread_cond_signal()也可能唤醒多个线程,而如果你同时只允许一个线程访问的话,就必须要使用while来进行条件判断,以保证临界区内只有一个线程在处理。


问题1:假设有10个线程都在pthread_cond_wait(&cond, &mut);当改变x,y的大小有,调用了pthread_cond_signal(&cond);
那么这10个线程都被唤醒了(应为上文说到规范要求pthread_cond_signal至少唤醒一个pthread_cond_wait上的线程);然后程序循环判定while(x<=y),这时x>y,那么这10个线程都跳过while循环,执行下面的代码了。但是上面解释说是唤醒了一个线程,其他9个线程将继续pthread_cond_wait(&cond, &mut)?

问题2:由问题1而来。当10个线程都被唤醒了,那么调用10次pthread_cond_wait(&cond, &mut).但是调用一次pthread_cond_wait(&cond, &mut)时,就解锁mut;
既然mut解锁了,那么其他9次mut怎么办


...全文
732 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq_26602805 2021-07-02
  • 打赏
  • 举报
回复 1

我有个问题就是pthread_cond_wait在最后跳出来前会再次加锁mut,现在10个线程都会加锁,那不就是同时竞争资源吗?有一个线程加锁了,其他线程在枷锁的过程不就同样阻塞吗?还需要while做什么?

shouso888 2013-11-11
  • 打赏
  • 举报
回复
楼主,这个问题有答案了么? 我还在疑惑中
江东橘子 2011-08-04
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 shanki_pm 的回复:]
我猜应该是这个意思:
假设有两个线程(我就用伪代码了):
//thread 1
while(0<x<10)
pthread_cond_wait();

//thread 2
while(5<x<15)
pthread_cond_wait();

如果某段时间内 x == 5,那么两个线程相继进入等待。

然后,另一个线程3:
修改x:x = 12
if(..) ……
[/Quote]

碰到的一个问题是:如果两个while的条件一样怎么办
江东橘子 2011-08-02
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 shanki_pm 的回复:]
我猜应该是这个意思:
假设有两个线程(我就用伪代码了):
//thread 1
while(0<x<10)
pthread_cond_wait();

//thread 2
while(5<x<15)
pthread_cond_wait();

如果某段时间内 x == 5,那么两个线程相继进入等待。

然后,另一个线程3:
修改x:x = 12
if(..) ……
[/Quote]

可能就是这个意思
江东橘子 2011-08-02
  • 打赏
  • 举报
回复
等号上面这段是大多数网上给pthread_cond_wait()加一个while为什么的解释:但是有些地方不太明白或者说没有解释清晰:
准备:1:pthread_cond_singal是唤醒至少一个线程的(而不是sinal的意思,仅仅唤醒一个线程)。
2:把下面while(x<y)当成thread1;while(x<z)当成thread2;if(x>y) 当成thread3.
解释:首先当thread1和thread2允许while时,发现条件都成立,那么就允许pthread_cond_wait();
然后当thread3时发送pthread_cond_singal;唤醒了thread2和thread3;唤醒后就会进行while判断。x>y,那么thread1不用pthread_cond_wait,就可以运行下去了。
而x<z不成立,继续执行pthread_cond_wait.所以就保证了只唤醒一个线程
justkk 2011-07-29
  • 打赏
  • 举报
回复
其他线程应该是在尝试加锁了,加锁成功后,从pthread_cond_wait返回,进入while判断了
qq_26602805 2021-07-02
  • 举报
回复
@justkk 请问都在尝试加锁,有一个线程加锁成功其他线程不就应该回阻塞吗?请问为什么还会从pthread_cond_wait返回?请问这样想的话我哪里错了
江东橘子 2011-07-29
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 justkk 的回复:]
1、10个线程不可能都从pthread_cond_wait中返回
因为返回前需要重新加锁,而只能有一个加锁成功
[/Quote]

1:其他线程也收到了这个信号,只能枷锁一个成功.那么其他线程怎么办? pthread_cond_wait是原子操作的
,如果这样的话他的操作不会被中断,那就继续枷锁了.

2:如果其他线程不枷锁,那么他们是继续pthread_cond_wait 等待信号,还是先while一次 判断了条件后在看是不是要执行pthread_cond_wait
qq_26602805 2021-07-02
  • 举报
回复 1
@江东橘子 请问对于第一个问题,那while不就可以用if代替while应该没用才对额,那为什么还要用while?
luo6620378xu 2011-07-29
  • 打赏
  • 举报
回复
纯粹帮顶!
南京浪人甲 2011-07-29
  • 打赏
  • 举报
回复
如果某段时间内 x == 8,那么两个线程相继进入等待。
笔误
南京浪人甲 2011-07-29
  • 打赏
  • 举报
回复
我猜应该是这个意思:
假设有两个线程(我就用伪代码了):
//thread 1
while(0<x<10)
pthread_cond_wait();

//thread 2
while(5<x<15)
pthread_cond_wait();

如果某段时间内 x == 5,那么两个线程相继进入等待。

然后,另一个线程3:
修改x:x = 12
if(..) phtread_cond_signal()

那么,虽然线程1、2都被唤醒了,但是,此时线程1仍然不满足while,只有线程2跳出while,
进入下面的操作。

以上纯属猜测。O(∩_∩)O~
woso 2011-07-28
  • 打赏
  • 举报
回复
hi, 看了你的问题,我发现我也没有仔细思考过这个问题

仔细google了一下,有了一下理解:

首先,我发现使用while的原因并不是因为好些文章所说的,是为了只唤醒一个线程,明显这是不可能的,的确pthread_cond_wait返回前需要重新加锁,但是只要条件成立,多个线程还是可能被唤醒

实际上,while的使用是因为"假唤醒"的问题,即,线程可能不是被cond_signal或cond_broadcast唤醒的,而是被中断换醒了

那为什么不能fix这样的问题,而是需要调用者来完成呢,http://vladimir_prus.blogspot.com/2005/07/spurious-wakeups.html 这篇文章给了非常详细的解释

希望对你能有帮助

欢迎大家拍砖(:
justkk 2011-07-28
  • 打赏
  • 举报
回复
1、10个线程不可能都从pthread_cond_wait中返回
因为返回前需要重新加锁,而只能有一个加锁成功
qq_26602805 2021-07-02
  • 举报
回复
@justkk 那请问while不是就没用为什么不用if
封牧之 2021-07-08
  • 举报
回复
@qq_26602805 假设线程接收到信号,进入pthread_cond_wait中,刚释放了锁,还未处理,假设此时条件已经被改变了,那么该线程不应该再处理下去,如果用if,则会继续处理下去,结果错误; 如果用while,会在pthread_cond_wait处理完时(即加锁了,等待释放),再判断一次条件是否正确,如果条件满足,则跳出while向下执行,如果不满足,则再一次while内运行,在pthread_cond_wait内阻塞,等到下一次信号到来。

23,209

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧