Hands-On Design Patterns with Swift
上QQ阅读APP看书,第一时间看更新

Example of a counting semaphore

In the following example, we'll use a semaphore to suspend the execution of the current thread until a long-running task has completed:

let semaphore = DispatchSemaphore(value: 0)
let queue = DispatchQueue(label: "com.run.concurrent",
attributes: .concurrent)

// Run a block 1 second of the future
queue.asyncAfter(deadline: DispatchTime.now() + 1) {
print("Will Signal")
semaphore.signal()
print("Did Signal")
}
print("Will Wait")

// wait for the semaphore, this suspends the current thread
semaphore.wait()
print("Done")

This will give us the following output:

Will Wait
Will Signal
Did Signal
Done

As you can see, this code successfully waited till the long-running operation was done, and signal() has been called on the semaphore.

Note that blocking the main thread with a semaphore may result in a deadlock if the semaphore is expected to be signaled on the main thread.

While semaphores are very powerful tools for coordinating the execution of many threads, sometimes, you may not know how many tasks you'll need to synchronize. Also, with semaphores, it is very easy to deadlock a thread as to continue execution; you'll need to balance all wait calls with signal calls. DispatchGroups are suited for this task.