-
-
Save jspahrsummers/dbd861d425d783bd2e5a to your computer and use it in GitHub Desktop.
// | |
// DON'T do this, or else you risk a deadlock (e.g., by accidentally performing it in a different order somewhere) | |
// | |
dispatch_async(firstQueue, ^{ | |
dispatch_sync(secondQueue, ^{ | |
// code requiring both queues | |
}); | |
}); |
// | |
// DO this instead | |
// | |
dispatch_queue_t concurrentQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT); | |
dispatch_set_target_queue(firstQueue, concurrentQueue); | |
dispatch_set_target_queue(secondQueue, concurrentQueue); | |
dispatch_barrier_async(concurrentQueue, ^{ | |
// code requiring both queues | |
}); |
@qnoid dispatch_set_target_queue
makes every block executed from firstQueue
or secondQueue
behave "as if" it were submitted to concurrentQueue
using dispatch_async
.
Being a target queue has no effect on the semantics of dispatch_barrier_*
functions. Barriers guarantee that nothing else on the queue is executing while the barrier block is running.
@jspahrsummers thanks!
@jspahrsummers
Hi, I have concerns about blocks already/still running for instance on firstQueue when dispatch_set_target_queue(firstQueue, concurrentQueue) is called. I suppose that after the call to dispatch_set_target_queue() they continue running on the original target queue. Hence, I fear that a dispatch_barrier on concurrentQueue used as the new target queue will not wait for those blocks running on their original target queues to complete before starting the barrier block.
What do you think about this ?
Marc
I have run tests and my fear has been confirmed: Execution of the block added via dispatch_barrier may start before blocks added to both queues complete if those blocks have been added before the call to dispatch_set_target.
A solution ensuring that nothing runs anymore on both queues when the barrier block starts is to use nested barriers:
dispatch_barrier_async(firstQueue, ^{
dispatch_barrier_sync(secondQueue, ^{
// barrier block
// when it is called, we are ensured that nothing is running anymore on both queues
});
});
Note that even if the outer barrier can be asynch
, the inner barriers should be synch
.
This solution has also the advantage not to mess with the original queue targets.
Can you please clarify how the dispatch_set_target_queue affects dispatch_barrier_async?
From the GCD doc it's not clear.