我正在使用内核共享工作队列,并且我有一个 delayed_work
我想重新安排立即运行的结构。
以下代码能否保证 delayed_work
会尽快运行吗?
cancel_delayed_work(work);
schedule_delayed_work(work, 0);
在工作已经在运行的情况下会发生什么?
cancel_delayed_work
将返回
0
,但我不确定
schedule_delayed_work
如果工作当前正在运行或未计划,则将执行此操作。
请您参考如下方法:
好吧,您知道他们所说的必要性是所有发明(或本例中的研究)之母。我真的需要这个答案,并通过挖掘 kernel/workqueue.c 得到了它。虽然答案大多包含在 doc comments结合 Documentation/workqueue.txt
,如果不阅读并发管理工作队列 (cmwq) 子系统的整个规范,它并没有清楚地说明,即使那样,一些信息已经过时了!
简短回答
Will [your code] guarantee that the delayed_work will run as soon as possible?
是(有以下警告)
What happens in a situation where the work is already running?
它将在当前运行的
delayed_work
之后的某个时间点运行。函数退出并在与最后一个相同的 CPU 上,尽管任何其他已在该工作队列中排队的工作(或到期的延迟工作)将首先运行。这是假设您尚未重新初始化
delayed_work
或
work_struct
对象并且您没有更改
work->func
化指针。
长答案
所以首先,
struct delayed_work
使用伪继承从
struct work_struct
派生通过嵌入
struct work_struct
作为它的第一个成员。这个子系统使用了一些惊人的原子位触发来实现一些严重的并发性。一个
work_struct
当它是
data
时是“拥有的”字段有
WORK_STRUCT_PENDING
位设置。当一个 worker 执行你的工作时,它
releases ownership并通过私有(private)
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()
如果工作仍在排队,则不先取消将不会导致任何更改,因此您必须先取消它。
编辑:哦,是的,如果您对
Documentation/workqueue.txt
中的讨论感到困惑关于
WQ_NON_REENTRANT
, 忽略它。该标志已被弃用和忽略,所有工作队列现在都是不可重入的。