8

我正在使用内核共享工作队列,并且我有一个delayed_work要重新安排以立即运行的结构。

下面的代码能保证delayed_work尽快运行吗?

cancel_delayed_work(work);
schedule_delayed_work(work, 0);

在工作已经在运行的情况下会发生什么?cancel_delayed_work将返回0,但我不确定schedule_delayed_work如果工作当前正在运行或计划外,该怎么办。

4

1 回答 1

10

好吧,您知道他们所说的必要性是所有发明(或本例中的研究)之母。我真的需要这个答案,并通过挖掘 kernel/workqueue.c 得到了它。尽管答案主要包含在与结合的文档注释Documentation/workqueue.txt中,但如果不阅读有关并发管理工作队列 (cmwq) 子系统的整个规范,则无法清楚地说明它,即使这样,某些信息也已过时!

简答

[您的代码] 会保证 delay_work 会尽快运行吗?

是(有以下警告)

在工作已经在运行的情况下会发生什么?

它将在当前运行的函数退出delayed_work的某个时间点运行,并在与最后一个函数相同的 CPU 上运行,尽管已经在该工作队列中排队的任何其他工作(或到期的延迟工作)将首先运行。这是假设你没有重新初始化你的delayed_workorwork_struct对象并且你没有改变work->function 指针。

长答案

所以首先,通过嵌入 a作为它的第一个成员,struct delayed_work使用伪继承来派生。这个子系统使用了一些惊人的原子位触发来实现一些严重的并发性。当A的字段设置了位时,它是“拥有的” 。当工作人员执行您的工作时,它会释放所有权并通过私有set_work_pool_and_clear_pending()函数记录最后一个工作池——这是 API 修改对象的最后一次(当然,直到您重新安排它)。调用做同样的事情。struct work_structstruct work_structwork_structdataWORK_STRUCT_PENDINGwork_structcancel_delayed_work()

因此,如果您cancel_delayed_work()在您的工作功能已经开始执行时调用,它会返回false(如宣传的那样),因为它不再为任何人所有,即使它可能仍在运行。但是,当您尝试使用 重新添加它时schedule_delayed_work(),它会检查工作以发现最后一个pool_workqueue,然后确定是否有任何pool_workqueue工作人员当前正在运行您的工作。如果它们是(并且您没有更改work->func指针),它只是将工作附加到队列中,pool_workqueue这就是它避免重新进入的方式!否则,它将在当前 CPU 的池中排队。(指针检查的原因work->func是允许work_struct对象的重用。)

但是请注意,如果工作仍在排队,则直接调用schedule_delayed_work()而不先取消它不会导致任何更改,因此您必须先取消它。

编辑:哦,是的,如果您对Documentation/workqueue.txtabout中的讨论感到困惑WQ_NON_REENTRANT,请忽略它。该标志已被弃用和忽略,所有工作队列现在都是不可重入的。

于 2013-06-27T06:52:11.943 回答