我正在使用内核共享工作队列,我有一个delayed_work
结构,我想重新安排立即运行。
以下代码是否可以保证delayed_work
能够尽快运行?
cancel_delayed_work(work);
schedule_delayed_work(work, 0);
在工作已经开始的情况下会发生什么? cancel_delayed_work
将返回0
,但如果作品当前正在投放或未安排,我不确定schedule_delayed_work
会做什么。
答案 0 :(得分:6)
嗯,你知道他们所说的必要性是所有发明的母亲(或在这种情况下的研究)。我真的需要这个答案,并通过挖掘kernel / workqueue.c得到它。虽然答案主要包含在doc comments和Documentation/workqueue.txt
中,但如果没有阅读并发管理工作队列(cmwq)子系统的整个规范,那么就没有明确说明,即使这样,一些信息也是如此。已经过时了!
简答
[您的代码]会保证delayed_work会尽快运行吗?
是(以下警告)
在工作已经开始的情况下会发生什么?
当当前正在运行的delayed_work
函数退出并且在与最后一个函数相同的CPU上时,它会在某个时刻运行,尽管任何其他工作已在该工作队列中排队(或延迟工作)即将到期)将首先运行。这假设您没有重新初始化delayed_work
或work_struct
对象,并且您没有更改work->func
指针。
长答案
首先,struct delayed_work
使用伪继承通过嵌入struct work_struct
作为其第一个成员来从struct work_struct
派生。该子系统使用一些惊人的原子位frigging来实现一些严重的并发性。当work_struct
字段设置为WORK_STRUCT_PENDING
时,data
为“拥有”。当工作人员执行您的工作时,它releases ownership并通过私有set_work_pool_and_clear_pending()函数记录最后一个工作池 - 这是API最后一次修改work_struct
对象(直到您重新安排它,当然)。调用cancel_delayed_work()
完全相同。
因此,如果在工作函数已经开始执行时调用cancel_delayed_work()
,它将返回false
(如所宣传的那样),因为它不再由任何人拥有,即使它可能仍在运行。但是,当您尝试使用schedule_delayed_work()
重新添加时,它会examine the work发现最后一个pool_workqueue
,然后查明pool_workqueue
的任何工作人员是否有目前正在运行你的工作如果它们是(并且您没有更改work->func
指针),它只是将工作附加到pool_workqueue
的队列中,这就是它如何避免重新入侵!否则,它会将它排队到当前CPU的池中。 (work->func
指针检查的原因是允许重用work_struct
对象。)
但是请注意,如果工作仍然排队,只需调用schedule_delayed_work()
而不首先取消它将导致 no 更改,因此您必须先取消它。
编辑:哦,是的,如果您对Documentation/workqueue.txt
关于WQ_NON_REENTRANT
的讨论感到困惑,请忽略它。不推荐使用和忽略此标志,并且所有工作队列现在都是非重新注册的。