Grand Central Dispatch: Queue vs Semaphore for controlling access to a data structure?

3.8k views Asked by At

I'm doing this with Macruby, but I don't think that should matter much here.

I've got a model which stores its state in a dictionary data structure. I want concurrent operations to be updating this data structure sporadically. It seems to me like GCD offers a few possible solutions to this, including these two:

  • wrap any code that accesses the data structure in a block sent to some serial queue
  • use a GCD semaphore, with client code sending wait/signal calls as necessary when accessing the structure

When the queues in the first solution are synchronously called, then it seems pretty much equivalent to the semaphore solution. Do either of these solutions have clear advantages that I'm missing? Is there a better alternative I'm missing?

Also: would it be straightforward to implement a read-write (shared-exclusive) lock with GCD?

3

There are 3 answers

0
Kazuki Sakamoto On

Serial Queue

  • Pros
    • there are not any lock
  • Cons
    • tasks can't work concurrently in the Serial Queue

GCD Semaphore

  • Pros
    • tasks can work concurrently
  • Cons
    • it uses lock even though it is light weight

Also we can use Atomic Operations instead of GCD Semaphore. It would be lighter than GCD Semaphore in some situation.

Synchronization Tools - Atomic Operations

0
Nick Hutchinson On

Guarding access to the data structure with dispatch_sync on serial queue is semantically equivalent to using a dispatch semaphore, and in the uncontended case, they should both be very fast. If performance is important, benchmark and see if there's any significant difference.

As for the readers-writer lock, you can indeed construct one on top of GCD—at least, I cobbled something together the other day here that seems to work. (Warning: there be dragons/not-well-tested code.) My solution funnels the read/write requests through an intermediary serial queue before submitting to a global concurrent queue. The serial queue is suspended/resumed at the appropriate times to ensure that write requests execute serially.

I wanted something that would simulate a private concurrent dispatch queue that allowed for synchronisation points—something that's not exposed in the public GCD api, but is strongly hinted at for the future.

0
greg On

Adding a warning (which ends up being a con for dispatch queues) to the previous answers.

You need to be careful of how the dispatch queues are called as there are some hidden scenarios that were not immediately obvious to me until I ran into them.

I replaced NSLock and @synchronized on a number of critical sections with dispatch queues with the goal of having lightweight synchronization. Unfortunately, I ran into a situation that results in a deadlock and I have pieced it back to using the dispatch_barrier_async / dispatch_sync pattern. It would seem that dispatch_sync may opportunistically call its block on the main queue (if already executing there) even when you create a concurrent queue. This is a problem since dispatch_sync on the current dispatch queue causes a deadlock.

I guess I'll be moving backwards and using another locking technique in these areas.