免费注册 查看新帖 |

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
21 [报告]
发表于 2014-08-21 21:00 |只看该作者
回复 18# gaojl0728

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

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

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

论坛徽章:
3
射手座
日期:2014-08-18 12:15:53戌狗
日期:2014-08-22 09:53:36寅虎
日期:2014-08-22 14:15:29
22 [报告]
发表于 2014-08-22 09:59 |只看该作者
回复 21# windoze


    pthread_cond_wait 那样是实现完全没问题,相当于在睡眠之前做一次double check, 避免了无谓的睡眠,
你确定"condition variable naked signal"能google到信号丢失? 能不能直接给啊

论坛徽章:
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
23 [报告]
发表于 2014-08-22 15:02 |只看该作者
回复 22# gaojl0728

懒人……

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

自己画个时序图。
   

论坛徽章:
3
射手座
日期:2014-08-18 12:15:53戌狗
日期:2014-08-22 09:53:36寅虎
日期:2014-08-22 14:15:29
24 [报告]
发表于 2014-08-22 15:50 |只看该作者
回复 23# windoze


    果然够专业, 论文都搬出来了, 下面是论文里面描述的信号丢失的情况,看到没后面有个解决方案:
解决方案就是在睡眠之前再检查一次有没有naked notify 产生,

- RACE problem, and notify can be lost. How?
  + since NOTIFY is just a hint
  + a process in the monitor, find <OK to proceed> to be FALSE, about to WAIT
        (of course, in this case, process is holding monitor lock)
  + now, device does a naked NOTIFY, it does not need to acquire lock
  + The WAIT then be done, and the NOTIFY is lost
- Note: this never happens if device requires to hold lock before doing NOTIFY
- Solution:
  + add a binary state to conditional variable.
  + whenever there is a naked notify, that bit is turned on
  + WAIT then check for that state before do a really wait
  + update to this state need to be atomic
  + this is similar to binary-semaphor
  
  
下面是linux的实现, 从”man pthread_cond_signal“ 搬出来的

              pthread_cond_wait(mutex, cond):
                  value = cond->value; /* 1 */
                  pthread_mutex_unlock(mutex); /* 2 */
                  pthread_mutex_lock(cond->mutex); /* 10 */
                  if (value == cond->value) { /* 11 */
                      me->next_cond = cond->waiter;
                      cond->waiter = me;
                      pthread_mutex_unlock(cond->mutex);
                      unable_to_run(me);
                  } else
                      pthread_mutex_unlock(cond->mutex); /* 12 */
                  pthread_mutex_lock(mutex); /* 13 */

              pthread_cond_signal(cond):
                  pthread_mutex_lock(cond->mutex); /* 3 */
                  cond->value++; /* 4 */
                  if (cond->waiter) { /* 5 */
                      sleeper = cond->waiter; /* 6 */
                      cond->waiter = sleeper->next_cond; /* 7 */
                      able_to_run(sleeper); /* 8 */
                  }
                  pthread_mutex_unlock(cond->mutex); /* 9 */

看起来linux的实现跟论文solution描述的产不多,真正的睡眠之前会检查下有没有signal产生, 也就是判断value == cond->value
如果有signal产生value == cond->value是false, linux不管signal 是不是naked, 在signal的时候会递增cond->value
这是安全的, 因为cond还有个内部锁cond->mutex保护
在cond->mutex保护下, 不管是pthread_cond_wait先跑还是pthread_cond_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
25 [报告]
发表于 2014-08-22 16:41 |只看该作者
回复 24# gaojl0728

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

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

论坛徽章:
3
射手座
日期:2014-08-18 12:15:53戌狗
日期:2014-08-22 09:53:36寅虎
日期:2014-08-22 14:15:29
26 [报告]
发表于 2014-08-22 16:48 |只看该作者
回复 25# windoze


    如果 ”不保证每次调用pthread_cond_signal的时候等待条件一定能满足“, 那就是编程错误了, 跟pthread_cond_signal是不是naked有什么关系么?

能不能把你肚子里的东西全部倒出来啊,一点一点挤累死我了。

论坛徽章:
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
27 [报告]
发表于 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里,否则就有可能丢信号。

论坛徽章:
0
28 [报告]
发表于 2014-08-23 04:06 |只看该作者
回复 27# windoze


    》 // <---假如此时计数器线程又执行了一次,count变成了11,信号就丢了

怎么可能?wait()返回之后就拿到了锁,到下一次wait()之前,计数器线程都不可能执行 count++。

论坛徽章:
0
29 [报告]
发表于 2014-08-23 04:12 |只看该作者
本帖最后由 giantchen 于 2014-08-22 12:13 编辑

回复 27# windoze


    》把signal放在锁里面,这样就可以保证不会丢失信号。
signal 不需要放到锁里面,虽然通常都放到锁里面。

而且你的wait线程写错了,如果wait()的时候计数器线程执行了两次(比如signal之后没有立刻调度,而是放入就绪队列),那么还是会错过count=10的情况。

论坛徽章:
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
30 [报告]
发表于 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才行了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP