Can I use a DispatchSemaphore to control a thread on main queue?

3.2k views Asked by At

Apparently I can only use DispatchSemaphore if I deal with different queues. But what if I want to run async code on the same queue (in this case the main queue).

let s = DispatchSemaphore(value : 0)
DispatchQueue.main.async {
   s.signal()
}
s.wait()

This snippet doesn't work, because the async code is also waiting, because the semaphore blocked the main queue. Can I do this with semaphore? Or do I need to run the async code on a different queue?

ps. I know I could use sync, instead of async and semaphore in this snippet. But This is just an example code to reproduce an async call.

2

There are 2 answers

5
dktaylor On BEST ANSWER

All of this in on the main thread, so the semaphore.signal() will never be called because the thread will stop on the semaphore.wait() and not continue on.

If you are trying to run some async code and have the main thread wait for it, run that code on a different queue and have it signal the semaphore when it's done, allowing the main thread to continue.

5
Jeff On

what if I want to run async code on the same queue (in this case the main queue).

Then use DispatchGroup instead. That is not what DispatchSemaphore is for.

Run this code in a playground.

import Foundation

let d = DispatchGroup()
var v:Int = 1
d.enter()
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
    v = 7
    d.leave()
}

d.notify(queue: DispatchQueue.main) {
    print("v = \(v)")
}

The output will be v = 7. If you comment out d.enter() and d.leave() then the output will be v = 1.

If I call async, don't I run that code on a different thread?

No, you need to understand thread run loops in general and iOS's Main Event Loop specifically.