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

2

9

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.

Nonsmoker answered 28/8, 2019 at 13:14 Comment(2)
The whole point of DispatchSemaphore is to control access to a resource across multiple threads. It makes no sense to use it with a single thread.Cretan
@Cretan If I call async, don't I run that code on a different thread?Nonsmoker
M
5

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.

Matisse answered 28/8, 2019 at 15:50 Comment(5)
However, when i call async (even if it's the same queue, in this case the main queue), don't I run the code on a different thread? Why the async code is blocked, if I call wait on the main thread?Nonsmoker
Calling async on the main queue will still be on the main thread, it just won’t be executed immediatelyMatisse
I see, so I guess there is no time to run the thread code in async, even if async is called before wait... ?Nonsmoker
Yep, the queue has not gotten to the async code block before the wait is calledMatisse
After 2 years, this comment helped me so much! Thank you both :)Wirra
B
-1

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.

Buckjumper answered 3/9, 2019 at 20:46 Comment(5)
Thanks. No offence, but I think you need to understand the questions and read the answers. 1) The question was already answered correctly and solved time ago. 2) I know there is DispatchGroup, but my question was about DispatchSemaphore to better understand this object. 3) The reason why your snippet works is that you can use notify() with dispatchGroup. If you called dispatchGroup.wait() you would have the same problem.Nonsmoker
4) Regarding the question "If I call async, don't I run that code on a different thread?", again this has already been answered, so no need to write "you need to understand..." cheersNonsmoker
@Nonsmoker The question and answer is not just for you, but for others that come after. To "run async code on the same queue" one should use DispatchGroup not DispatchSemaphore. This question is an X,Y question. Stopping the main thread is most times a bug.Buckjumper
@Nonsmoker about "need to understand", all your questions indicated fundamental ignorance of run loops and threading. I provided doc link to run loops to be helpful because those docs are hard to find. And your comment above about dispatchGroup.wait indicates you still do not understand.Buckjumper
Your answer and these last comments definitely indicate a conceited attitude. The question was already answered in the question comments and in the original accepted answer. The additional (not strictly required) information that you provide (DispatchGroup) is incomplete: what about DispatchWorkItem as possible solution then? The link to "docs are hard to find" are actually easy to find: just google "Apple threads" and you'll see the result in the second position. Finally, I welcome your opinion about my "fundamental ignorance" on the topic, always useful to get some feedback.Nonsmoker

© 2022 - 2024 — McMap. All rights reserved.