Dispatch_barrier_async and serial queue in GCD, what're differences between them?
Asked Answered
V

3

14

I found that the working mechanism of dispatch_barrier_async is that it is only executed once all of the blocks previously added to the queue have been completed. It works similar to the serial queue.

Therefore, I do not distinguish what the differences between these two of running modes in GCD.

enter image description here

Vertex answered 1/10, 2016 at 4:19 Comment(0)
C
34

dispatch_barrier_[a]sync are meant to be used with a concurrent queue. They are also meant to be used along with calls to dispatch_[a]sync.

The common usage is the "multi-readers, one writer" pattern. You setup a concurrent queue. For "reader" blocks, you use dispatch_[a]sync. For "writer" blocks, you use dispatch_barrier_[a]sync.

This setup allows concurrent reading but only allows one writer at a time and no reading while the writing is happening.

Compare this with a serial queue where only one block at a time can ever happen.

Collegium answered 1/10, 2016 at 4:28 Comment(1)
so should I use .async on writer or reader? My understanding is .sync on Reader and .async on writer. Because on reader we need to return the value we are trying to read, and only .sync will guarantee there will be a return.Coarctate
L
22

Your diagram perfectly illustrates how a barrier works. Seven blocks have been dispatched to a concurrent queue, four without a barrier (blocks 0 through 3 in your diagram), one with a barrier (the maroon colored "barrier block” numbered 4 in your diagram), and then two more blocks without a barrier (blocks 5 and 6 in your diagram).

As you can see, the first four run concurrently, but the barrier block will not run until those first four finish. And the last two will not start until the "barrier block" finishes.

Compare that to a serial queue, where none of the tasks can run concurrently:

comparison

If every block dispatched to the concurrent queue was dispatched with a barrier, then you're right, that it would be equivalent to using a serial queue. But the power of barriers comes into play only when you combine barrier dispatched blocks with non-barrier dispatched blocks on concurrent queue. So, when you want to enjoy the concurrent behavior, don't use barriers. But where a single block needs serial-like behavior on concurrent queue, use a barrier.

One example is that you might dispatch 10 blocks without barriers, but then add an 11th with a barrier. Thus the first 10 may run concurrently with respect to each other, but the 11th will only start when the first 10 finish (achieving a "completion handler" behavior).

Or as rmaddy said (+1), the other common use for barriers is where you're accessing some shared resource for which you will allow concurrent reads (without barrier), but must enforce synchronized writes (with barrier). In that case, you often use dispatch_sync for the reads and dispatch_barrier_async for the writes.

Lemal answered 1/10, 2016 at 4:49 Comment(1)
this is gold. Really appreciate itCoarctate
E
0

#swift5

Both of them are used for synchronization, so the serial queue make sure all your jobs are done in a stack for example, if you have A,B,C,D tasks, they will be executed in the same order if they are sync or async sync blocks the other operation from executing until the sync block is done.

Barrier: allow you to do sync operation in stack however it allows you to do the async operation for reading these values so it's more powerful when it comes to data structure implementations you have only one writer with multiple readers.

func asyncReading() {
    DispatchQueue.global(qos: .background)
        .async(group: .init(), qos: .background, flags: .barrier) {
            /// Read code.
        }
}

func syncWriting() {
    DispatchQueue.global(qos: .background)
        .sync(group: .init(), qos: .background, flags: .barrier) {
            /// Write code.
        }
}
Erose answered 23/12, 2020 at 21:8 Comment(4)
are you going to explain a bit more? Code-only answers are not recommended...Apery
Sure, I will update my answer with an explanation, I assumed people read the other answers. thanks.Erose
Then perhaps, just quote the important part of theirs. But also like what is .sync(group: .init() no other answer has that.Apery
so should I use .async on writer or reader? My understanding is .sync on Reader and .async on writer. Because on reader we need to return the value we are trying to read, and only .sync will guarantee there will be a return.Coarctate

© 2022 - 2024 — McMap. All rights reserved.