Reputation: 802
I have to stop my code for one second in order to get server databases synced before continuing.
All code snippets below are run from main thread.
I used this first:
// code 1
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
// dummy
}
// stuff
Outcome obviously not as desired since stuff is executed immediately. I'd like stuff to run delayed after the code block (not nice, but there's a reason for it).
// code 2
let group = DispatchGroup()
group.enter()
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
group.leave()
}
group.wait()
// stuff
Deadlock!
Questions 1 : Why is main queue without DispatchGroup working and locks in conjunction with DispatchGroup?
// code 3
let group = DispatchGroup()
group.enter()
DispatchQueue.global().asyncAfter(deadline: .now() + 1.0) {
group.leave()
}
group.wait()
// stuff
This works as desired!
Question 2 : Why is global queue required with DispatchGroup to make stuff run delayed?
I read this here:
https://stackoverflow.com/a/42773392/3657691/ https://stackoverflow.com/a/28821805/3657691/ https://stackoverflow.com/a/49287115/3657691/
Upvotes: 2
Views: 1405
Reputation: 1479
I am going to assume that you are running these snippets on the main thread, as this is most probably the case from the issue description.
Dispatch queues are basically task queues, so a queue has some tasks enqueued. Let's see what is on the main queue when you are executing the snippet generating a deadlock.
asyncAfter
which will enqueue another task (the closure containing group.leave()
) on the main queue, after the specified deadline.Now the task being executed (1.) is being blocked by the call to group.wait()
, and it's going to block the whole main queue until it finishes execution. This means the enqueued task (2.) will have to wait until the first one finishes. You can see here that the 2 tasks will block each other:
For question number 2, using a global queue (or literally any other queue other than the one our current code is being executed on - in this example the main queue), will not block the asyncAfter
task (obviously, because it's being scheduled on another queue which is not blocked, thus it gets the chance to be executed).
This is true for serial dispatch queues (the main queue being a serial queue as well). Serial dispatch queues will execute their tasks serially, that is only one at a time.
On the other hand, for a concurrent dispatch queue, this scenario won't result in a deadlock, because the asyncAfter
task won't be blocked by the waiting task. That's because concurrent dispatch queues don't wait for the task being executed to be finished to schedule the next enqueued task.
This would even be a good exercise to try to run this scenario on a serial queue, and then on a concurrent queue to observe the differences
Upvotes: 2