如何在主队列调度同步无死锁?如何在主队列调度同步无死锁?(How to dispatch on ma

2019-05-13 16:16发布

我需要派遣块上的主队列,同步进行。 我不知道我目前的主线程或没有上运行。 天真的解决方案如下:

dispatch_sync(dispatch_get_main_queue(), block);

但是,如果我目前在主队列段运行的内部,这个调用创建了一个僵局。 (同步调度等待块完成,但该块甚至没有开始运行,因为我们都在等待当前的完成。)

最明显的下一步是检查当前队列:

if (dispatch_get_current_queue() == dispatch_get_main_queue()) {
    block();
} else {
    dispatch_sync(dispatch_get_main_queue(), block);
}

这工作,但它的丑陋。 之前,我至少后面躲起来,一些自定义的功能,是不是有这个问题更好的解决办法? 我强调,我买不起异步分派块 - 应用程序是在将异步分派块将得到执行“为时已晚”的情况。

Answer 1:

我需要我的Mac和iOS应用中相当经常使用这样的事情,所以我用下面的辅助函数(最初在描述这个答案 ):

void runOnMainQueueWithoutDeadlocking(void (^block)(void))
{
    if ([NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}

你通过调用

runOnMainQueueWithoutDeadlocking(^{
    //Do stuff
});

这是一个很值得你在上面描述的过程中,我已经说过了谁已经独立制作像这样为自己其他几个开发商。

我用[NSThread isMainThread]而不是检查dispatch_get_current_queue()因为该功能警告部警告一次对使用该身份检测和呼叫是在IOS 6弃用 。



Answer 2:

对于同步在主队列或主线程(也就是不一样的),我使用:

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)
    }
}


Answer 3:

我最近开始在UI更新遇到了僵局。 这导致我这个堆栈溢出问题,这导致了我实现runOnMainQueueWithoutDeadlocking基于公认的答案型的辅助功能。

真正的问题,虽然是从块更新UI时,我曾误用dispatch_sync而不是dispatch_async以获取UI更新主队列。 容易做到代码完成,或许很难在事后通知。

因此,为他人阅读这样一个问题: 如果不需要同步执行 ,只需使用dispatch_**a**sync将避免你可能会间歇性地击中了僵局。



文章来源: How to dispatch on main queue synchronously without a deadlock?