当我阅读 ldd3 第 6 章时,我对下面显示的代码感到困惑:
while (spacefree(dev) == 0) { /* full */ DEFINE_WAIT(wait);
up(&dev->sem);
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
PDEBUG("\"%s\" writing: going to sleep\n",current->comm);
prepare_to_wait(&dev->outq, &wait, TASK_INTERRUPTIBLE);
if (spacefree(dev) == 0)
schedule( );
finish_wait(&dev->outq, &wait);
if (signal_pending(current))
return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
}
if (spacefree(dev) == 0)
和 schedule()
之间是否存在竞争条件。如果 spacefree(dev)
函数在 if 语句刚刚结束时返回非零值,则进程可能会失去唯一被唤醒的机会。谁能告诉我这些代码背后的机制是什么?
顺便说一下,我在 Linux Kernel Development 中找到了另一个代码片段,它与上面的代码片段类似。然而,一些细节有所不同。
DEFINE_WAIT(wait);
add_wait_queue(q, &wait);
while (!condition) { /* condition is the event that we are waiting for */
prepare_to_wait(&q, &wait, TASK_INTERRUPTIBLE);
if (signal_pending(current))
/* handle signal */
schedule();
}
finish_wait(&q, &wait);
最不同的是添加了 add_wait_queue()
函数,它没有出现在第一个代码片段中。
第二个区别是,在第二个片段的while
语句中,schedule()
之前没有条件测试。为什么?
第三个区别是signal_pending()
函数的位置,一个在schedule()
之前,一个在之后。
为什么会存在这样的差异?
最佳答案
来自 LDD3 第 6 章:
“通过在设置进程状态后检查我们的条件,我们可以免受所有 可能的事件顺序。如果我们等待的条件已经发生 在设置进程状态之前,我们注意到在此检查中并没有真正休眠。如果 此后发生唤醒,无论我们是否有,进程都可以运行 居然睡着了。”
关于linux - 手动将进程置于 sleep 状态时是否存在竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28029079/