【微信群技术讨论】无效唤醒问题
本文是原「蜗窝讨论区」的历史存档(2017-07-18),来自版块「Linux kernel技术问答」,共 1 帖。讨论区已停止服务,此处仅供查阅。
这是《linux内核设计与实现》中的一段代码,如果在while之后prepare_to_wait之前另一个线程做了wake_up,是不是有问题? DEFINE_WAIT(wait);―――――――――――――1
add_wait_queue(q, &wait);―――――――――――2 while ( !condition) {――――――――――――――3 ------在这里,其他线程唤醒了这个task怎么办??? prepare_to_wait(&q, &wait, TASK_INTERRUPTIBLE);――――4 if (signal_pending(current))―――――――――5 进行信号处理 Schedule(;――――――――――――――――6 } finish_wait(&q, &wait);―――――――――――――7
过程分析: 1、 定义一个wait queue entry 2、 将该wait queue entry挂入等待队列(不修改进程状态) 3、 检查一下条件如何?condition其实是和该task等待的事件相关的,如果condition等于true,那么说明事件发生了,那么进程没有必要进行睡眠,直接到finish_wait 4、 修改进程状态,如果有需要,将该task重新挂入等待队列 5、 如果进程状态是TASK_INTERRUPTIBLE,那么需要处理pengding的信号 6、 发起调度,抢占当前的task的执行 7、 唤醒之后会去3处重新判定condition,如果是true,那么调用finish_wait修改状态是TASK_RUNNING,并从等待队列中摘下该wait queue entry。
在条件检查(步骤3)和进程状态设定(步骤4)之间,如果其他cpu的进程调用wake up函数执行唤醒,那么这次唤醒其实是无效的唤醒,因为在随后的步骤4中,进程状态被该回成TASK_INTERRUPTIBLE并挂入等待队列,之后调用Schedule函数导致该task被无情的移出runqueue。而在prepare之后(步骤4)发生wake up是没有问题的,因为wakeup会把task置成TASK_RUNNING状态,这样schedule的时候就不会把该task移出runqueue,从而不会有问题。
