22

It may be a dumb question but I need to ask and clear this up for myself.

To submit a block onto a queue for execution, use the functions dispatch_sync and dispatch_async. They both take a queue and a block as parameters. dispatch_async returns immediately, running the block asynchronously, while dispatch_sync blocks execution until the provided block returns. Here are some situations:

Situation 1

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);    
dispatch_async(queue, ^{
    [self goDoSomethingLongAndInvolved];
    dispatch_async(queue, ^{
        NSLog(@"this is statement1");

    });
});

Situation 2

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);    
dispatch_sync(queue, ^{
    [self goDoSomethingLongAndInvolved];
    dispatch_sync(queue, ^{
        NSLog(@"this is statement1");

    });
});

Situation 3

{
    [super viewDidLoad];
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);    
    dispatch_async(queue, ^{
        [self goDoSomethingLongAndInvolved];
        dispatch_sync(queue, ^{
            NSLog(@"this is statement1");

        });
    });

Situation 4

{
    [super viewDidLoad];
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);    
    dispatch_sync(queue, ^{
        [self goDoSomethingLongAndInvolved];
        dispatch_async(queue, ^{
            NSLog(@"this is statement1");

        });
    });

}

And goDoSomethingLongAndInvolved is

-(void)goDoSomethingLongAndInvolved {
    NSLog(@"goDoSomethingLongAndInvolved");
}

I tried to run them in Xcode but I cant see the difference at all.

So my questions are:

  1. What's the main difference between these situations?
  2. What if I replace queue with dispatch_get_main_queue()?
tranvutuan
  • 6,089
  • 8
  • 47
  • 83
  • 1
    When you say 'you can't see the difference', what do you mean? Difference in speed of execution? Given that your `goDoSomethingLongAndInvolved` method will take nanoseconds, I'm not surprised if you can't see a speed difference. – davidf2281 Aug 15 '13 at 21:28
  • 1
    Have you tried setting breakpoints in and around the blocks? – Sebastian Aug 15 '13 at 21:55
  • writing a long post vs. reading Apple's docs, 1:0, but... the second one would have been easier. http://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/dispatch_sync.3.html – holex Aug 17 '13 at 22:41

1 Answers1

17

The dispatch_sync statement waits until the block it covers is executed completely. dispatch_async returns immediately and proceeds to the next line of code, so everything inside is happening in parallel.

If queue was a serial queue created by yourself, then:

Situation 1 - The root block returns immediately. Inside it waits for [self go....], and then goes to dispatch_async, which returns immediately as well.

Situation 2 - If queue was a serial queue, then there would be a dead lock since it will wait for itself to finish executing. Since you are dealing with asynchronous one, that block will be executed in parallel. (Thanks, @Ken Thomases)

Situation 3 - No need in dispatch_sync here. It causes the deadlock.

Situation 4 - Waits for [self ...], then returns immediately.

If you replace the queue with main queue, then remember to not dispatch_sync on main queue, because it will cause a deadlock (it will not if dispatched not from main thread, thanks @Ken Thomases).

To understand it better, replace your function with:

-(void)goDoSomethingLongAndInvolved:(NSString *)message {
    for(int i = 0; i < 50; ++i) {
        NSLog(@"%@ -> %d", message, i); 
    }
}

You will clearly see what's going on every time, whether it waits or not. Good luck.

dreamzor
  • 5,795
  • 4
  • 41
  • 61
  • @ dreamzor: all are clear but situation 2. the outer `dispatch_sync` will wait for its block. Firstly, `goDoSomethingLongAndInvoled` is completed (`goDoSomethingLongAndInvolved` will be shown out ) then next is inner `dispatch_sync`. Like said, it will wait for `NSLog(@"this is statement1")` completed. Now `this is statement` will be printed out. So `dispatch_sync` is done. Eventually, outer `dispatch_sync` is done. That is why I am confused why it causes deadlock at here. – tranvutuan Aug 16 '13 at 02:19
  • 5
    Situation 2 does not cause a deadlock. It would if the `queue` were a serial queue, but it's not. So, the inner task can run even while the outer task is still in-progress. It's also not true that `dispatch_sync()` to the main queue will *always* deadlock. It will only deadlock if it was dispatched from the main thread. That makes the main thread wait for itself. – Ken Thomases Aug 16 '13 at 06:09
  • You guys are right, I'm sorry. I usually create my own serial `queue`, so it was based on such an experience :) – dreamzor Aug 16 '13 at 09:08
  • 2
    If you correct your claim about situation 2 in the answer, I'll remove my downvote. – Ken Thomases Aug 16 '13 at 19:32
  • Why do it have to wait for [self go..] in Situation 1? It's concurrent queue. @dreamzor – Elsammak Feb 06 '17 at 11:38
  • 1
    @Elsammak it waits inside the queue until it calls the next async call - there is no async in calling [self go...] itself within the queue. – dreamzor Feb 06 '17 at 11:41
  • But the queue itself is concurrent so it may call [self go..] then go to the block to execute it. – Elsammak Feb 06 '17 at 11:44
  • @dreamzor It violates the definition of concurrent queue, doesn't it? – Elsammak Feb 06 '17 at 14:03