Search code examples
iosobjective-cmacoscocoagrand-central-dispatch

Concurrent insertion of blocks into concurrent queue


I want to add blocks A, B, C into global concurrent queue. Immediately after that I want to add barrier to the same queue.

I expect that A, B, C all be called in some order but when all blocks terminate the barrier will be invoked.

How can I guarantee that NO additional block will be inserted in the middle of this sequence? For example, if in some other place I deploy block X on the same queue, I do not want it to be executed before the barrier.

Can the same solution be available both on MacOS and iOS?


Solution

  • Barriers don’t work on global queues. Create your own custom concurrent queue. As the dispatch_barrier_async documentation says:

    The queue you specify should be a concurrent queue that you create yourself using the dispatch_queue_create function. If the queue you pass to this function is a serial queue or one of the global concurrent queues, this function behaves like the dispatch_async function.

    Then anything dispatched to that queue after the barrier won’t run until after the barrier. So dispatch A, B, and C. Then dispatch D with a barrier. Then dispatch X. The A, B, and C will run concurrently with respect to each other, when they’re done then D will run, and when D is done, X will run. That’s how it works, on both macOS and iOS. Just create your own custom concurrent queue.

    dispatch_queue_t queue = dispatch_queue_create("com.company.app.queue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{ 
        NSLog(@"start - A!\n");  
        sleep(4);  
        NSLog(@"end - A!\n");
    });
    
    dispatch_async(queue, ^{  
        NSLog(@"start - B!\n");  
        sleep(2);  
        NSLog(@"end - B!\n"); 
    });
    
    dispatch_async(queue, ^{  
        NSLog(@"start - C!\n");  
        sleep(3);  
        NSLog(@"end - C!\n"); 
    });
    
    dispatch_barrier_async(queue, ^{  
        NSLog(@"Barrier - D\n");  
    });
    
    dispatch_async(queue, ^{  
        NSLog(@"start - X!\n");  
        sleep(3);  
        NSLog(@"end - X!\n"); 
    });