如何在没有死锁的情况下同步调度主队列? [英] How to dispatch on main queue synchronously without a deadlock?
问题描述
我需要同步在主队列上调度一个块。我不知道我目前是在主线程上运行还是不运行。天真的解决方案如下所示:
I need to dispatch a block on the main queue, synchronously. I don’t know if I’m currently running on the main thread or no. The naive solution looks like this:
dispatch_sync(dispatch_get_main_queue(), block);
但如果我目前在主队列上运行的块内,此调用会造成死锁。 (同步调度等待块完成,但块甚至没有开始运行,因为我们正在等待当前块完成。)
But if I’m currently inside of a block running on the main queue, this call creates a deadlock. (The synchronous dispatch waits for the block to finish, but the block does not even start running, since we are waiting for the current one to finish.)
显而易见的下一个步骤是检查当前队列:
The obvious next step is to check for the current queue:
if (dispatch_get_current_queue() == dispatch_get_main_queue()) {
block();
} else {
dispatch_sync(dispatch_get_main_queue(), block);
}
这很有效,但很难看。在我至少把它隐藏在一些自定义功能之前,是不是有更好的解决方案来解决这个问题?我强调我不能异步调度块 - 应用程序处于异步调度块将执行得太晚的情况。
This works, but it’s ugly. Before I at least hide it behind some custom function, isn’t there a better solution for this problem? I stress that I can’t afford to dispatch the block asynchronously – the app is in a situation where the asynchronously dispatched block would get executed "too late".
推荐答案
我需要在我的Mac和iOS应用程序中经常使用这样的东西,所以我使用以下帮助函数(最初在这个答案):
I need to use something like this fairly regularly within my Mac and iOS applications, so I use the following helper function (originally described in this answer):
void runOnMainQueueWithoutDeadlocking(void (^block)(void))
{
if ([NSThread isMainThread])
{
block();
}
else
{
dispatch_sync(dispatch_get_main_queue(), block);
}
}
您可以通过
runOnMainQueueWithoutDeadlocking(^{
//Do stuff
});
这几乎是你在上面描述的过程,我和其他几位开发人员谈过为自己独立制作这样的东西。
This is pretty much the process you describe above, and I've talked to several other developers who have independently crafted something like this for themselves.
我使用 [NSThread isMainThread]
而不是检查 dispatch_get_current_queue()
,因为警告部分对于该功能一旦警告不要使用它进行身份测试和 iOS 6中不推荐使用该呼叫。
I used [NSThread isMainThread]
instead of checking dispatch_get_current_queue()
, because the caveats section for that function once warned against using this for identity testing and the call was deprecated in iOS 6.
这篇关于如何在没有死锁的情况下同步调度主队列?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!