Why does DispatchGroup interfere with main queue?

geohei

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/

Vlad Rusu

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.

  1. The main queue has a task executing (the one executing the snippet)
  2. Then you call 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:

  • the first one (1.) will wait until the second one (2.) releases the dispatch group
  • the second one (2.) will wait until the first one (1.) finishes execution so it can be scheduled

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

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

why does a local PrintWriter interfere with another local PrintWriter?

Multiprocessing queue - Why does the memory consumption increase?

Does Git interfere with SVN?

Why does "position: relative" interfere with "transform: scale"?

Why does "#define A" interfere with "namespace A{}"?

Why does a nested self-capturing function interfere with isKnownUniquelyReferenced(_:)?

Why my DispatchGroup's wait always timeout?

Why does enabling undefined behaviour sanitization interfere with optimizations?

Why private queue dispatch _async update UI after main queue update UI?

Accessing main queue via DispatchGroup vs. DispatchQueue

Why does my Navbar interfere with my Stripe token creation?

Why does socket interfere with selenium?

Why does optimizing with the -O(1/2/3) option interfere with scanf()?

Swift - Why is DispatchGroup not working in this function?

Why is DispatchGroup deinit never called?

Does DispatchGroup wait forever?

Why does publisher declares queue a in Pika RabbitMQ?

Implementing a Web Api Controller - why does use of IDisposable interfere with routing?

Why does my firewall (iptables) interfere in my bridge (brctl)?

Does the operation system interfere with browser rendering?

Why does this queue behave like this?

Maven deploy-file goal: Why does the first execution interfere with the second one?

Why does the NEG instruction interfere with the Carry Flag?

Why does Queue Uses LinkedList Constructor in Java

Does requestAnimationFrame interfere CSS transitions?

gevent queue does not raise Empty when queue.get invoked inside greenlets (other than the main greenlet)?

Why does my queue event delay not working

Why does remapping key interfere with FormatTime?

Why isn't the queue updating on the main thread?