I found this in the documentation (last chapter):
Do not call the dispatch_sync function from a task that is executing on the same queue that you pass to your function call. Doing so will deadlock the queue. If you need to dispatch to the current queue, do so asynchronously using the dispatch_async function.
Also, I followed the link that you provided and in the description of dispatch_sync I read this:
Calling this function and targeting the current queue results in deadlock.
So I don‘t think it‘s a problem with GCD, I think the only sensible approach is the one you invented after discovering the problem.