默认情况下,在创建 时DispatchSourceTimer
,默认并发队列用于调度定时器事件和取消。
有趣的是,即使在事件处理程序已经触发之后,单次计时器仍然会调度对取消处理程序的调用。
所以考虑下面的代码:
let timer = DispatchSource.makeTimerSource()
timer.setEventHandler {
print("event handler")
}
timer.setCancelHandler {
print("cancel handler")
}
timer.schedule(wallDeadline: .now())
timer.activate()
DispatchQueue.global().asyncAfter(deadline: .now() + .seconds(1)) {
timer.cancel()
}
输出:
event handler
cancel handler
现在根据文档,调用cancel()
应该阻止事件句柄执行,但是假设调用cancel()
与内部事件处理程序的调用同步是否安全?
异步取消调度源,防止对其事件处理程序块的任何进一步调用。
我想确保调用其中一个或另一个,但不能同时调用两者,所以我修改了我的代码并将取消处理程序包装到DispatchWorkItem
,我从事件处理程序内部取消:
let timer = DispatchSource.makeTimerSource()
var cancelHandler = DispatchWorkItem {
print("cancel handler")
}
timer.setEventHandler {
cancelHandler.cancel()
print("event handler")
}
timer.setCancelHandler(handler: cancelHandler)
timer.schedule(wallDeadline: .now())
timer.activate()
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
timer.cancel()
}
但是,我不太确定这段代码是线程安全的。这段代码是否可能容易出现竞争条件,取消处理程序与事件处理程序同时执行但在相应事件DispatchWorkItem
被取消之前执行?
我意识到我可能可以添加锁,或者使用串行队列,我的问题是向熟悉libdispatch
内部结构的人提问。