3

I am newer to iPhone development and going through GCD concept for multithreading.

'dispatch_queue_t' creates a serial queue and I have read that a serial queue will only execute one job at a time. GCD is intended to execute multiple tasks simultaneously then why serial queue even exist ?

For example, I want to do 2 task. Task A and Task B. I create one serial queue for executing both these tasks. I am doing this in the main queue. Here is the code what I am doing:

dispatch_queue_t my_serial_queue = dispatch_queue_create("queue_identifier", 0);

    dispatch_sync(my_serial_queue, ^{
        NSLog(@"Task 1");
    });

    dispatch_sync(my_serial_queue, ^{
        NSLog(@"Task 2");
    });

Now, As per the rule, both the task will execute serially as it is serial queue i.e. Task A is executed first and then after Task A is finished, Task B will be executed. And also it is giving me the same output in log.

So, my question is, what if I want to execute both the tasks simultaneously ? If the answer of this question is to create another serial queue for Task B then the code should be structured like this:

dispatch_queue_t my_serial_queue_1 = dispatch_queue_create("queue_identifier_1", 0);
dispatch_queue_t my_serial_queue_2 = dispatch_queue_create("queue_identifier_2", 0);


    dispatch_sync(my_serial_queue_1, ^{
        NSLog(@"Task 1");
    });

    dispatch_sync(my_serial_queue_2, ^{
        NSLog(@"Task 2");
    });

I am getting the same output. Reason is I am using 'dispatch_sync' call instead of 'dispatch_async' call. But as I am running both the tasks in different queues, shouldn't they execute simultaneously ? If not, then why should we create a different queue ? I might have used the same queue by 'dispatch_async' call for executing both the tasks simultaneously.

I really need answer of this question because, before designing structure of my multi-tasking Apps in future, it will guide me better.

halfer
  • 19,824
  • 17
  • 99
  • 186
NSPratik
  • 4,714
  • 7
  • 51
  • 81

2 Answers2

5

Your confusion is pretty much entirely because you're using dispatch_sync. dispatch_sync is not a tool for getting concurrent execution, it is a tool for temporarily limiting it for safety.

Once you're using dispatch_async, you can get concurrency either by having more than one queue, or by using concurrent queues. The purpose of using serial queues in this context is to control which work is done simultaneously.

Consider the following very silly example:

__block void *shared = NULL;
for (;;) {
    dispatch_async(aConcurrentDispatchQueue, ^{
        shared = malloc(128);
        free(shared);
    }
}

this will crash, because eventually, two of the concurrently executing blocks will free 'shared' in a row. This is a contrived example obviously, but in practice, nearly all shared mutable state must not be changed concurrently. Serial queues are your tool for making sure that you do that.

Summarizing:

  • When the work in your blocks is truly independent and thread-safe, and purely computational, go ahead and use dispatch_async to a concurrent queue
  • When you have logically independent tasks that each consist of several related blocks, use a serial queue for each task
  • When you have work that accesses shared mutable state, do those accesses in dispatch_sync()ed blocks on a serial queue, and the rest of the work on a concurrent queue
  • When you need to do UI-related work, dispatch_async or dispatch_sync to the main queue, depending on whether you need to wait for it to finish or not
Catfish_Man
  • 41,261
  • 11
  • 67
  • 84
  • 1
    @ Catfish_Man: So in short, if I want to execute 2 tasks (those I mentioned) totally concurrently, I either should (1) Use 'dispatch_async' within serial queue or (2) Create 2 concurrent queues for those 2 tasks rather than creating 2 queues by 'dispatch_queue_t' (because 'dispatch_queue_t' creates serial queue). – NSPratik Sep 11 '14 at 08:10
  • @ Catfish_Man: Assume that these 2 tasks are totally independent. – NSPratik Sep 11 '14 at 08:11
  • One concurrent queue, or two serial queues. Serial queues order everything on them, but are concurrent with respect to every other queue. Concurrent queues don't order things on them at all. – Catfish_Man Sep 11 '14 at 08:38
  • @ Catfish_Man: I mentioned two alternatives in my first comment. Are those solutions of what I want ? – NSPratik Sep 11 '14 at 08:53
  • No, I was correcting you. You said two concurrent queues, you either want two serial queues or *one* concurrent queue. – Catfish_Man Sep 11 '14 at 17:26
1

'dispatch_queue_t' doesn't create anything. dispatch_queue_t is a dispatch queue, either serial or concurrent.

dispatch_queue_create has two parameters. The second parameter decides whether the queue that it creates is a serial or concurrent queue. But usually you don't create concurrent queues yourself but use one of the three existing concurrent queues.

dispatch_sync dispatches a block on a queue and waits until the block is finished. It should be obvious that this very much limits concurrency. You should almost always use dispatch_async.

Sequential queues can only execute one block at a time. It should be obvious that this very much limits concurrency. Sequential queues are still useful when you need to perform various blocks one after another, and they can be executed concurrently with blocks in other queues.

So for maximum use of processors use dispatch_async on a concurrent queue. And there is no need to create more than one concurrent queue. It's concurrent. It can run any number of blocks concurrently.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
  • @ gnasher729: Statement by you: "Sequential queues are still useful when you need to perform various blocks one after another, and they can be executed concurrently with blocks in other queues." To make it practical, I made a demo by creating 2 serial queues. But these queues don't execute concurrently. Blocks of queue B does not execute until all blocks from A completes their execution. I even tried by making both of these queues concurrent, still I got same result. Why can't those queues run concurrently until I make dispatch_async call ? (Even I create concurrent queue) – NSPratik Sep 11 '14 at 12:51
  • 1
    If you use dispatch_sync (first block), dispatch_sync (second block), then dispatch_sync itself waits until first block is finished, and dispatch_sync (second block) only executes once the first block is finished. If you use it like that, it doesn't matter much what the queues are doing. – gnasher729 Nov 08 '14 at 22:31