ios 如何在没有死锁的情况下同步调度主队列?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10330679/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to dispatch on main queue synchronously without a deadlock?
提问by zoul
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”.
这有效,但它很丑陋。在我至少将它隐藏在一些自定义函数后面之前,是否有更好的解决方案来解决这个问题?我强调我不能异步分派块——应用程序处于异步分派的块将“太晚”执行的情况。
回答by Brad Larson
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):
我需要在我的 Mac 和 iOS 应用程序中经常使用这样的东西,所以我使用以下帮助函数(最初在这个答案中描述):
void runOnMainQueueWithoutDeadlocking(void (^block)(void))
{
if ([NSThread isMainThread])
{
block();
}
else
{
dispatch_sync(dispatch_get_main_queue(), block);
}
}
which you call via
你通过
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.
这几乎就是你上面描述的过程,我已经和其他几位开发人员交谈过,他们为自己独立制作了这样的东西。
I used [NSThread isMainThread]
instead of checking dispatch_get_current_queue()
, because the caveats section for that functiononce warned against using this for identity testing and the call was deprecated in iOS 6.
我使用[NSThread isMainThread]
而不是检查dispatch_get_current_queue()
,因为该函数的警告部分曾经警告不要使用它进行身份测试,并且该调用在 iOS 6 中已弃用。
回答by JollyJinx
For syncing on the main queue or on the main thread (that is not the same) I use:
为了在主队列或主线程(不一样)上同步,我使用:
import Foundation
private let mainQueueKey = UnsafeMutablePointer<Void>.alloc(1)
private let mainQueueValue = UnsafeMutablePointer<Void>.alloc(1)
public func dispatch_sync_on_main_queue(block: () -> Void)
{
struct dispatchonce { static var token : dispatch_once_t = 0 }
dispatch_once(&dispatchonce.token,
{
dispatch_queue_set_specific(dispatch_get_main_queue(), mainQueueKey, mainQueueValue, nil)
})
if dispatch_get_specific(mainQueueKey) == mainQueueValue
{
block()
}
else
{
dispatch_sync(dispatch_get_main_queue(),block)
}
}
extension NSThread
{
public class func runBlockOnMainThread(block: () -> Void )
{
if NSThread.isMainThread()
{
block()
}
else
{
dispatch_sync(dispatch_get_main_queue(),block)
}
}
public class func runBlockOnMainQueue(block: () -> Void)
{
dispatch_sync_on_main_queue(block)
}
}
回答by pkamb
I recently began experiencing a deadlock during UI updates. That lead me this Stack Overflow question, which lead to me implementing a runOnMainQueueWithoutDeadlocking
-type helper function based on the accepted answer.
我最近开始在 UI 更新期间遇到死锁。这导致我出现了 Stack Overflow 问题,这导致我runOnMainQueueWithoutDeadlocking
根据接受的答案实现了一个-type 辅助函数。
The real issue, though, is that when updating the UI from a block I had mistakenly used dispatch_sync
rather than dispatch_async
to get the Main queue for UI updates. Easy to do with code completion, and perhaps hard to notice after the fact.
然而,真正的问题是,当从一个块更新 UI 时,我错误地使用了dispatch_sync
而不是dispatch_async
获取 UI 更新的主队列。代码完成很容易,但事后可能很难注意到。
So, for others reading this question: if synchronous execution is not required, simply using dispatch_**a**sync
will avoid the deadlock you may be intermittently hitting.
因此,对于阅读此问题的其他人:如果不需要同步执行,只需使用即可dispatch_**a**sync
避免您可能间歇性地遇到的死锁。