我正在使用内核共享工作队列,并且我有一个delayed_work
要重新安排以立即运行的结构。
下面的代码能保证delayed_work
尽快运行吗?
cancel_delayed_work(work);
schedule_delayed_work(work, 0);
在工作已经在运行的情况下会发生什么?cancel_delayed_work
将返回0
,但我不确定schedule_delayed_work
如果工作当前正在运行或计划外,该怎么办。
我正在使用内核共享工作队列,并且我有一个delayed_work
要重新安排以立即运行的结构。
下面的代码能保证delayed_work
尽快运行吗?
cancel_delayed_work(work);
schedule_delayed_work(work, 0);
在工作已经在运行的情况下会发生什么?cancel_delayed_work
将返回0
,但我不确定schedule_delayed_work
如果工作当前正在运行或计划外,该怎么办。
好吧,您知道他们所说的必要性是所有发明(或本例中的研究)之母。我真的需要这个答案,并通过挖掘 kernel/workqueue.c 得到了它。尽管答案主要包含在与结合的文档注释Documentation/workqueue.txt
中,但如果不阅读有关并发管理工作队列 (cmwq) 子系统的整个规范,则无法清楚地说明它,即使这样,某些信息也已过时!
简答
[您的代码] 会保证 delay_work 会尽快运行吗?
是(有以下警告)
在工作已经在运行的情况下会发生什么?
它将在当前运行的函数退出后delayed_work
的某个时间点运行,并在与最后一个函数相同的 CPU 上运行,尽管已经在该工作队列中排队的任何其他工作(或到期的延迟工作)将首先运行。这是假设你没有重新初始化你的delayed_work
orwork_struct
对象并且你没有改变work->func
tion 指针。
长答案
所以首先,通过嵌入 a作为它的第一个成员,struct delayed_work
使用伪继承来派生。这个子系统使用了一些惊人的原子位触发来实现一些严重的并发性。当A的字段设置了位时,它是“拥有的” 。当工作人员执行您的工作时,它会释放所有权并通过私有set_work_pool_and_clear_pending()函数记录最后一个工作池——这是 API 修改对象的最后一次(当然,直到您重新安排它)。调用做同样的事情。struct work_struct
struct work_struct
work_struct
data
WORK_STRUCT_PENDING
work_struct
cancel_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.txt
about中的讨论感到困惑WQ_NON_REENTRANT
,请忽略它。该标志已被弃用和忽略,所有工作队列现在都是不可重入的。