我们如何在 Swift 中实现等待/通知

use*_*119 7 multithreading synchronization swift

在Java中,我们可以这样做:

synchronized(a) {
    while(condition == false) {
        a.wait(time);
    }
    //critical section ...
    //do something
}
Run Code Online (Sandbox Code Playgroud)

上面是一个条件同步块,它等待条件成功才能执行关键部分。

当执行 a.wait 时(例如 100 毫秒),线程在该持续时间内退出临界区,并且由对象 a 执行同步的其他一些临界区,这使得条件为真。

当条件成功时,当前线程下次进入临界区并评估条件时,循环退出并执行代码。

需要注意的要点: 1. 多个临界区由同一个对象同步。2. 线程仅在等待期间不处于临界区。一旦wait出来,线程又回到临界区。

下面是在 Swift 4 中使用 DispatchSemaphore 执行相同操作的正确方法吗?

while condition == false {
    semaphore1.wait(duration)
}
semaphore1.wait()
//execute critical section
semaphore1.signal()
Run Code Online (Sandbox Code Playgroud)

当我们进入临界区时,条件可能会被修改。

因此,我们可能必须执行如下操作才能实现 Java 行为。在 Swift 中是否有更简单的方法来做到这一点?

while true {
    //lock
    if condition == false {
        //unlock
        //sleep for sometime to prevent frequent polling
        continue
    } else {
        //execute critical section
        //...
        //unlock
        break
    }
}
Run Code Online (Sandbox Code Playgroud)

Luc*_*tti 10

信号量

你可以用以下方法解决这个问题DispatchSemaphore。

我们来看看这段代码。这里我们有一个semaphore, storagetype 属性String?和一个串行队列

let semaphore = DispatchSemaphore(value: 0)
var storage: String? = nil
let serialQueue = DispatchQueue(label: "Serial queue")
Run Code Online (Sandbox Code Playgroud)

制片人

func producer() {
    DispatchQueue.global().asyncAfter(deadline: .now() + 3) {
        storage = "Hello world!"
        semaphore.signal()
    }
}
Run Code Online (Sandbox Code Playgroud)

这里我们有一个函数:

  1. 等待3秒
  2. 将“Hello world”写入存储
  3. 通过信号量发送信号

消费者

func consumer() {
    serialQueue.async {
        semaphore.wait()
        print(storage)
    }
}
Run Code Online (Sandbox Code Playgroud)

这里我们有一个函数

  1. 等待来自信号量的信号
  2. 打印存储内容

测试

现在我要在函数consumer 之前运行producer

consumer()
producer()
Run Code Online (Sandbox Code Playgroud)

结果

Optional("Hello world!")
Run Code Online (Sandbox Code Playgroud)

它是如何工作的?

func consumer() {
    serialQueue.async {
        semaphore.wait()
        print(storage)
    }
}
Run Code Online (Sandbox Code Playgroud)

函数体consumer()异步执行到串行队列中。

serialQueue.async {
    ...
}
Run Code Online (Sandbox Code Playgroud)

这相当于你的synchronized(a). 事实上,根据定义,串行队列将同时运行一个闭包。

闭包内的第一行是

semaphore.wait()
Run Code Online (Sandbox Code Playgroud)

因此闭包的执行被停止,等待信号量发出绿灯。

这是在不同的队列(不是主队列)上发生的,因此我们不会阻塞主线程。

func producer() {
    DispatchQueue.global().asyncAfter(deadline: .now() + 3) {
        storage = "Hello world!"
        semaphore.signal()
    }
}
Run Code Online (Sandbox Code Playgroud)

现在 Producer() 被执行。它在与主队列不同的队列上等待 3 秒,然后填充storage并通过信号量发送信号。

终于consumer()收到信号了,可以跑最后一行了

print(storage)
Run Code Online (Sandbox Code Playgroud)

操场

如果您想在 Playground 中运行此代码,请记住

import PlaygroundSupport
Run Code Online (Sandbox Code Playgroud)

并运行这条线

PlaygroundPage.current.needsIndefiniteExecution = true
Run Code Online (Sandbox Code Playgroud)


use*_*119 -2

回答我的问题。

在下面的伪代码中使用 NSLock 的实例来锁定和解锁。

while true {
    //lock
    if condition == false {
        //unlock
        //sleep for sometime to prevent frequent polling
        continue
    } else {
        //execute critical section
        //...
        //unlock
        break
    }
}
Run Code Online (Sandbox Code Playgroud)