linux唤醒丢失问题(Lost Wake-Up Problem)

linux中的唤醒丢失问题,是同步机制中的一个经典问题。
在下面的文章中:
https://www.linuxjournal.com/article/8144
第一个问题比较好理解:

Process A:
1  spin_lock(&list_lock);
2  if(list_empty(&list_head)) {
3      spin_unlock(&list_lock);
4      set_current_state(TASK_INTERRUPTIBLE);
5      schedule();
6      spin_lock(&list_lock);
7  }
8
9  /* Rest of the code ... */
10 spin_unlock(&list_lock);

Process B:
100  spin_lock(&list_lock);
101  list_add_tail(&list_head, new_node);
102  spin_unlock(&list_lock);
103  wake_up_process(processa_task);

如果先执行完进程A的第3行,然后再执行进程B的100~103行,接着再执行进程A的第4行及之后的代码。这样进程A将进入睡眠状态,进程B前面的那次唤醒操作就丢失了。

第二个问题就没有这么好理解:

4253  /* Wait for kthread_stop */
4254  set_current_state(TASK_INTERRUPTIBLE);
4255  while (!kthread_should_stop()) {
4256          schedule();
4257          set_current_state(TASK_INTERRUPTIBLE);
4258  }
4259  __set_current_state(TASK_RUNNING);
4260 return 0;

这份代码是linux-2.6.11/kernel/sched.c,migration_thread线程里的。其他地方会置上停止标志并唤醒它,让其退出。
直接这么看代码,没有看出问题在哪里,跟唤醒丢失有什么关系。

先改写一下代码,去掉set_current_state的部分,代码变成:

4253  /* Wait for kthread_stop */
4254  while (!kthread_should_stop()) {
4255          schedule();
4256  }
4257 return 0;

乍一看,也没有问题,其他地方置上停止标志,唤醒它,等它被调度到了,它就退出了。
问题是,本意是让这个线程大部分时间睡眠,等其他地方置上停止标志,唤醒它了,它才醒来并退出。但上面这份代码,就会频繁的(只要调度到了)测试停止标志,与本意不符。

为了这个线程大部分时间都睡眠,就改一下代码:

4253  /* Wait for kthread_stop */
4254  while (!kthread_should_stop()) {
4255          set_current_state(TASK_INTERRUPTIBLE);
4256          schedule();
4257  }
4258 return 0;

这时候就看出问题了,如果这个线程执行完4254行,在执行4255行之前,其他地方置上停止标志,并尝试唤醒此线程。由于此线程虽然被调度出去了,但还是TASK_RUNNING状态,因此唤醒操作无效。然后此线程被调度进来,并把状态设置成TASK_INTERRUPTIBLE,然后再触发调度进入睡眠。至此,前面那个唤醒操作就丢失了。

如果只在一处将线程状态设置成TASK_INTERRUPTIBLE,都是有隐患的(先不考虑最后设成TASK_RUNNING的部分)。
比如,在最开始处设置:

4253  /* Wait for kthread_stop */
4254  set_current_state(TASK_INTERRUPTIBLE);
4255  while (!kthread_should_stop()) {
4256          schedule();
4257  }
4258 return 0;

如果此线程睡眠之后,被信号唤醒了,它的状态就变成TASK_RUNNING,此后就会频繁的测试停止标志了。
如果在schedule之后设置:

4253  /* Wait for kthread_stop */
4254  while (!kthread_should_stop()) {
4255          schedule();
4256          set_current_state(TASK_INTERRUPTIBLE);
4257  }
4258 return 0;

这个问题好像也不大?只是跟最开始正确的代码相比,正确的代码第一次进入schedule就睡眠了,而这里的代码,第一次进入schedule时还是TASK_RUNNING,后面还会被正常调度到,第二次进入schedule时才开始睡眠。
另外,正确的代码语义比较完整,每次测试停止标志前都设置了TASK_INTERRUPTIBLE,而这里的代码的语义相对就不完整,第一次没有设置TASK_INTERRUPTIBLE,后面才开始设置TASK_INTERRUPTIBLE。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,701评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,649评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,037评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,994评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,018评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,796评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,481评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,370评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,868评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,014评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,153评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,832评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,494评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,039评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,437评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,131评论 2 356

推荐阅读更多精彩内容