How to dispatch on main queue synchronously without a deadlock? How to dispatch on main queue synchronously without a deadlock? ios ios

How to dispatch on main queue synchronously without a deadlock?


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

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 function once warned against using this for identity testing and the call was deprecated in iOS 6.


For syncing on the main queue or on the main thread (that is not the same) I use:

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


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.

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.

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.