免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: kaede_1
打印 上一主题 下一主题

[C] Linux下条件变量的信号丢失指的是什么? [复制链接]

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
1 [报告]
发表于 2014-08-15 22:28 |显示全部楼层
我能说你们忘了把pthread_cond_signal包在lock中间了吗?

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
2 [报告]
发表于 2014-08-21 16:57 |显示全部楼层
回复 16# gaojl0728

pthread_cond有可能会spurious wakeup,如果不把pthread_cond_signal用lock包起开会有race condition,导致丢信号。
自己在纸上画画时序图你就明白了。

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
3 [报告]
发表于 2014-08-21 21:00 |显示全部楼层
回复 18# gaojl0728

pthread_cond_signal进来就会锁住cond的内部mutex

这句话是错的,如果pthread_cond_wait会在没有signal或者broadcast的情况下**,就真的会丢信号了。

网上搜“condition variable naked signal”你就知道了

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
4 [报告]
发表于 2014-08-22 15:02 |显示全部楼层
回复 22# gaojl0728

懒人……

http://pages.cs.wisc.edu/~thanhdo/qual-notes/sync/sync0-mesa.txt

自己画个时序图。
   

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
5 [报告]
发表于 2014-08-22 16:41 |显示全部楼层
回复 24# gaojl0728

唉,话说如果程序员不保证每次调用pthread_cond_signal的时候等待条件一定能满足,你在pthread的实现里做再多工作有啥用泥?

画个时序图你就知道了,不骗你。

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
6 [报告]
发表于 2014-08-22 17:17 |显示全部楼层
本帖最后由 windoze 于 2014-08-22 17:39 编辑

回复 26# gaojl0728

举个无脑的例子:
假定有个计数器线程每次把计数器加一,有个监视线程,一个看计数器是不是10的倍数
那么监视线程你会这么写:

  1. pthread_mutex_lock(mtx);
  2. while(1) {
  3.     pthread_cond_wait(cv, mtx);
  4.     if(!(count%10)) { /* do something */ }
  5. }
  6. pthread_mutex_unlock(mtx);
复制代码
计数器线程你可能会这么写:

  1. count++;
  2. pthread_cond_signal(cv, mtx);
复制代码
你要问为啥不在这里检查条件?因为不方便啊,要是我有天想要看20的倍数,我只需要改一处就好了,如果在这里也检查条件我需要改两处,还有可能会漏一个。
当然这样有race condition对不对?写count没有与读count互斥,所以你可能会这样:

  1. pthread_mutex_lock(mtx);
  2. count++;
  3. pthread_mutex_unlock(mtx);
  4. pthread_cond_signal(cv, mtx);
复制代码
这样count的race condition没有了,但是你仔细想想,在监视线程中:

  1. ...
  2.     // 假如此时count==10,监视线程调用了signal
  3.     pthread_cond_wait(cv, mtx);
  4.     // <---假如此时计数器线程又执行了一次,count变成了11,信号就丢了
  5.     if(!(count%10)) { /* do something */ }
  6. ...
复制代码
要想防止这种现象发生,你必须保证在上面的这个点决不会执行计数器线程。
因为cond_wait返回后就自动获得了锁,所以你可以用这一点进行互斥,让计数器线程一直等到下次进入pthread_cond_wait,此时锁自动释放了。
所以你需要把计数器线程写成这样:

  1. pthread_mutex_lock(mtx);
  2. count++;
  3. pthread_cond_signal(cv, mtx);
  4. pthread_mutex_unlock(mtx);
复制代码
把signal放在锁里面,这样就可以保证不会丢失信号。

**条件和实际检查的条件不一致就会造成所谓的“spurious wakeup”,在这里计数器每次有变化的时候都会**等待线程,但等待线程实际上要一直等到计数器变为10的倍数,这一部分是你自己的程序逻辑,pthread的实现没法帮你。
凡是会有假**的情况,你必须保证pthread_cond_signal不是naked,也就是说必须包在lock里,否则就有可能丢信号。

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
7 [报告]
发表于 2014-11-16 01:15 |显示全部楼层
回复 29# giantchen

嗯,脑子有点晕,正确的wait写法是这样:

  1. pthread_mutex_lock(mtx);
  2. while(...) {
  3.     // ...
  4.     while(count%10!=0) {  // A
  5.         // B
  6.         pthread_cond_wait(cv, mtx);  // C
  7.     }
  8.     /* do something */
  9. }
  10. pthread_mutex_unlock(mtx);
复制代码
问题是即便写成这样,如果signal那边不加锁,也一样会丢信号。
假设某次执行到C点时count==8,此时有一个人把count加一然后signal,程序执行到A点,会继续循环。
假如在B点又有人把count加一并signal,此时虽说条件满足了(count==10),但这边的wait还没开始,而条件判断已经过去了,这就丢失了一个信号,并且无法再找回来。
即便之后又有人把count加一并signal,count就等于11了,要执行do something得等到count==20才行了。

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
8 [报告]
发表于 2014-11-16 20:06 |显示全部楼层
回复 32# folklore

你说得对啊,最近家里事太多,休息严重不足,整个人都不好了……

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
9 [报告]
发表于 2014-11-18 13:03 |显示全部楼层
回复 34# giantchen

  1.     while(count%10!=0) {
  2.         pthread_cond_wait(cv, mtx);
  3.     }
复制代码
这样写wait错了?脑子有点晕,没反应过来有什么问题。

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
10 [报告]
发表于 2014-11-19 09:46 |显示全部楼层
回复 36# giantchen

嗯,你说的对,我编造的例子有问题,pthread_mutex不一定是FIFO的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP