Why would dispatching synchronously onto the current queue cause a deadlock?

I'm going through a Ray Wenderlich tutorial that says that dispatching synchronously onto the current queue will cause a deadlock. I'm not able to see how and why that is. Would someone explain this to me?

Accepted Reply

You can think of

dispatch_sync
and being composed of two operations:
  1. An async dispatch of the block to the queue.

  2. A wait for that block to finish.

If you

dispatch_sync
to the current queue then you deadlock because:
  • The block won’t run because the current queue is busy running your code.

  • Your code will never complete because it’s waiting for the block to run.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Replies

You can think of

dispatch_sync
and being composed of two operations:
  1. An async dispatch of the block to the queue.

  2. A wait for that block to finish.

If you

dispatch_sync
to the current queue then you deadlock because:
  • The block won’t run because the current queue is busy running your code.

  • Your code will never complete because it’s waiting for the block to run.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

In general, be very careful with dispatch_sync. There are only a handful of places where it is useful. If you aren't careful, you could have a sequence like this: foo -> bar > do > re > me > fa > so > dispatch_sync(bar) and you're done.


dispatch_sync is useful to dispatch a block onto a private serial queue to make some structure thread-safe. But that structure and your use of dispatch_sync needs to be relatively simple. All you are trying to do is serialize access to a data structure.

Is dispatch_sync the same as someDispatchQueue.sync { }?

What do you mean by "and you're done"? Do you mean you deadlock? And I don't follow what your notation means with "foo -> bar > do > re > me > fa > so > dispatch_sync(bar)". Is each of those elements a block?

Yes. I mean deadlock. Each of those elements are function/method calls. Don't assume that just because you don't directly call dispatch_sync() that some other function further down the call chain doesn't eventually call that method. Such method calls can even go across processes and potentially across networks in client/server systems.


dispatch_sync, or any variant thereof, is useful for making a data structure or object thread safe. I mentioned this in your other thread. The "sync" part is really not a good name. This method is for taking some kind of messy, asynchronous behaviour in the real world and shoving it through a funnel until only a single block at a time can execute. It creates serialized behaviour when used with a serial queue.


You can use it with a concurrent queue, but then you are making that messy, asynchronous world world a bit more complicated. You can also use it with the main thread of your app. This way, you take that messy, asynchronous world, making it more complicated still, and give the end user a beach ball cursor for good measure. On a phone, I guess the display would just lock up. I'm not saying any of this is guaranteed, just a lot more likely to happen if you don't have an extremely good understanding of what GCD is doing. Let me assure you, no one has that kind of understanding of what GCD is doing.

Yes. It's the Obj-C name of the same API function.