8
{
    dispatch_queue_t myQueue = dispatch_queue_create("com.mycompany.myqueue", 0);

    dispatch_sync(myQueue, ^{

        //Do EXTREME PROCESSING!!!
        for (int i = 0; i< 100; i++) {
            [NSThread sleepForTimeInterval:.05];
            NSLog(@"%i", i);
        }

        dispatch_sync(dispatch_get_main_queue(), ^{
            [self updateLabelWhenBackgroundDone];
        });
    });
}

I am getting a deadlock here. According to Apple documentation

"dispatch_sync": "Submits a block to a dispatch queue for synchronous execution. Unlike dispatch_async, this function does not return until the block has finished. Calling this function and targeting the current queue results in deadlock.".

However, I do the outer dispatch_sync on myQueue and then I do inner ditpatch_sync on a different queue which is `main_queue.

Can not find out the reason for the deadlock. Any comments/help are appreciated here.

tranvutuan
  • 6,089
  • 8
  • 47
  • 83
  • Where is "over here"? – trojanfoe Aug 18 '13 at 08:25
  • 2
    I don't believe this is a duplicate of their earlier question, which called a nested `dispatch_sync()` on the same queue. This is calling on two different queues, so it is a slightly, but significantly, different question. I'm reopening it as a result. – Brad Larson Aug 18 '13 at 16:35

3 Answers3

13

If you dispatch_sync to myQueue like that and the call happens on the main thread, then dispatch_sync will, if possible, execute the block right there and not on a new worker thread like dispatch_async would. You're not guaranteed to get a separate worker thread for your queue.

The block then runs on the main thread until it hits your second dispatch_sync call, which happens to target the main queue. That queue can't be serviced, since there's already a block running on it, and that's where you end up in a deadlock.

If that's your problem, i.e. the first dispatch_sync is indeed coming from the main thread, then you should switch to dispatch_async. You wouldn't want to block the main thread with the long-running "EXTREME PROCESSING" operation.

Marc Liyanage
  • 4,601
  • 2
  • 28
  • 28
  • so based on what you have just said, dispatch_async will execute the task on new worker thread and dispatch_sync will execute the task on main thread. Correct me if I am wrong – tranvutuan Aug 18 '13 at 22:46
  • 3
    dispatch_async will execute the block on a worker thread, but it could also be the main thread, if you happen to target the main queue directly or indirectly (via target queues). It's an implementation detail, and it's really best if you don't depend on it and don't think in terms of threads, but in terms of queues, and which parts of your code need to be performed asynchronously or synchronously. – Marc Liyanage Aug 19 '13 at 04:38
  • Do I understand correct, that one of decisions may be a check [NSThread isMainThread]. If YES, the first dispatch_async should be replaced on dispatch_sync? – Valentin Shamardin Sep 12 '18 at 08:51
7

You are calling dispatch_sync twice. The first time suspends the main thread waiting for your block to complete. The block then suspends the background thread with the second call which tries to push back to the main thread (which will never process the block from its queue because it's suspended). Both threads are now waiting for each other.

At least one of the calls needs to be dispatch_async.

Wain
  • 118,658
  • 15
  • 128
  • 151
2

I had similar problems and none of these solutions worked. I asked someone smarter than me.

My problem was I was spawning a dispatching an async worker block, and then displaying a progress window. Calls back into the main thread via

dispatch_sync(dispatch_get_main_queue(), ^{})

failed as did async calls.

The explanation was that the main thread was no longer in 'commons mode' because of the modal window. I replaced my calls to the main thread with this....

CFRunLoopPerformBlock(([[NSRunLoop mainRunLoop] getCFRunLoop]), (__bridge CFStringRef)NSModalPanelRunLoopMode, ^{
        //Update UI thread.

    });
John Twigg
  • 7,171
  • 4
  • 20
  • 20