Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deadlock with dispatch_sync

{
    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.

like image 752
tranvutuan Avatar asked Aug 18 '13 08:08

tranvutuan


3 Answers

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.

like image 115
Marc Liyanage Avatar answered Oct 20 '22 05:10

Marc Liyanage


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.

like image 7
Wain Avatar answered Oct 20 '22 06:10

Wain


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.

    });
like image 2
John Twigg Avatar answered Oct 20 '22 07:10

John Twigg