7

I know you might find this an odd question, but I'm just learning GCD and I want to fully understand all its aspects. So here it is:

Is there ever any reason to dispatch a task SYNC on the CURRENT QUEUE?

For example:

    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(...);
    dispatch_async(concurrentQueue, ^{
       //this is work task 0

       //first do something here, then suddenly:

       dispatch_sync(concurrentQueue, ^{
               //work task 1
       });

       //continue work task 0
    });

I understand one thing: if instead of concurrentQueue I use a serial queue, then I get a deadlock on that serial queue, because work task 1 cannot start until the work task 0 is finished (because of the serial queue that guarantees order of execution), and in the same time work task 0 cannot continue its execution because it waits for the SYNC dispath function to return (please correct me if I'm wrong, that would make me a total noob).

So coming back to the original idea, is there any difference whatsoever between the code above and the same code where instead of calling the dispatch_sync function I simply write work task 1 code directly?

Jano
  • 62,815
  • 21
  • 164
  • 192
Bogdan Alexandru
  • 5,394
  • 6
  • 34
  • 54

2 Answers2

7

No. I can't think of a reason to ever dispatch_sync on the same concurrent queue you're already on. If you do that, GCD will just immediately invoke your block, in-line, on the same thread, as if you had called it directly. (I checked.) And as you pointed out, doing that on a serial queue will deadlock you.

ipmcc
  • 29,581
  • 5
  • 84
  • 147
  • I'm grasping desperately, but how about if you definitely wanted a particular task to occur on a certain queue, but the issuing task may or may not occur on that queue? The only problem then is coming up with a realistic scenario in which the queue is concurrent. – Tommy Oct 04 '13 at 23:01
  • @Tommy the question was: is dispatch_sync to the same queue superfluous?. Your question seems to be, is there a point to dispatch_sync to a concurrent queue that is potentially different from the current one?. Yes, if you want your next line of code to happen after the code of your dispatch_sync. A realistic scenario would be: a complex hierarchy of queues and/or code that retargets queues (because your block can end up anywhere). – Jano Oct 04 '13 at 23:51
  • @Jano You haven't understood my comment. It's related to ipmcc's answer so I'm responding to "I can't think of a reason to ever dispatch_sync on the same concurrent queue you're already on", not the original question. A reason might be: you definitely want a task done on that queue. You don't know whether you're already on it. Yes, you could write code to check that, but you'd just be duplicating code Apple has already written so there's a good argument not to do so. – Tommy Oct 05 '13 at 00:10
  • @Tommy You need to be careful with this: If you know for sure that the queue you want the task done on (Q1) is concurrent, then you could do this. But if you don't know what queue you're currently executing on (Q?), it's possible you might not know whether Q1 is concurrent or not. If it's serial, and it happens that Q1 == Q?, then `dispatch_sync`'ing to it will deadlock you. You might be able to sort this out using `dispatch_queue_[get|set]_specific` and `dispatch_get_specific` but that assumes that no one else is using that feature for anything you'd be clobbering. – ipmcc Oct 07 '13 at 12:49
  • @ipmcc I absolutely agree. And, for the record, just about the only contrived situation I've conjured involves something on one of the global queues wanting to dispatch further work as `DISPATCH_QUEUE_PRIORITY_LOW` but not knowing its own priority. Maybe you've got a web service that involves expensive parsing and then bookkeeping to store for reuse. The parsing always looks the same but you dispatch it as either `DISPATCH_QUEUE_PRIORITY_HIGH` or `DISPATCH_QUEUE_PRIORITY_LOW` depending on whether it's for the user interface now or for the future. You always do the bookkeeping as low priority. – Tommy Oct 07 '13 at 20:03
3

Assume this queue for all examples:

dispatch_queue_t queue = dispatch_queue_create(“com.somecompany.queue”, nil);

Situation 1 - OK

dispatch_async(queue, ^{
    [self goDoSomethingLongAndInvolved];
    dispatch_async(queue, ^{
        NSLog(@"Situation 1");
    });
});

Situation 2 - Not OK! Deadlock!

dispatch_sync(queue, ^{
    [self goDoSomethingLongAndInvolved];
    dispatch_sync(queue, ^{
        NSLog(@"Situation 2”); // NOT REACHED!  DEADLOCK!
    });
});

Situation 3 - Not OK! Deadlock!

dispatch_async(queue, ^{
    [self goDoSomethingLongAndInvolved];
    dispatch_sync(queue, ^{
        NSLog(@"Situation 3"); // NOT REACHED!  DEADLOCK!
    });
});

Situation 4 - OK

dispatch_sync(queue, ^{
    [self goDoSomethingLongAndInvolved];
    dispatch_async(queue, ^{
        NSLog(@"Situation 4");
    });
});

Basically dispatch_sync does not like to be on the inside.

Only dispatch_asyncs can go inside.

TenaciousJay
  • 6,750
  • 3
  • 45
  • 48