我们如何在 Swift 中实现等待/通知 [英] How do we implement wait / notify in Swift

查看:126
本文介绍了我们如何在 Swift 中实现等待/通知的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

synchronized(a) {而(条件 == 假){a.等待(时间);}//临界区...//做一点事}

上面是一个条件同步块,它等待一个条件成功执行临界区.

当 a.wait 被执行时(比如 100 毫秒),线程在这段时间内退出临界区 &执行对象 a 同步的一些其他临界区,这使条件为真.

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

注意事项:1. 多个临界区被同一个对象同步.2. 一个线程只在等待期间不在临界区.等待结束后,线程再次处于临界区.

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

while 条件 == false {semaphore1.wait(持续时间)}semaphore1.wait()//执行临界区semaphore1.signal()

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

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

while true {//锁如果条件 == 假 {//开锁//休眠一段时间,防止频繁轮询继续} 别的 {//执行临界区//...//开锁休息}}

解决方案

信号量

你可以用DispatchSemaphore来解决这个问题.

让我们看看这段代码.这里我们有一个 semaphorestorage 类型的 String? 属性和一个串行队列

let semaphore = DispatchSemaphore(value: 0)var 存储:字符串?= 零让serialQueue = DispatchQueue(标签:串行队列")

制作人

func producer() {DispatchQueue.global().asyncAfter(deadline: .now() + 3) {storage = "你好世界!"semaphore.signal()}}

这里有一个函数:

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

消费者

func 消费者() {serialQueue.async {信号量.wait()打印(存储)}}

这里有一个函数

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

测试

现在我要运行 consumer BEFORE producer 函数

消费者()生产者()

结果

Optional("Hello world!")

它是如何工作的?

func 消费者() {serialQueue.async {信号量.wait()打印(存储)}}

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

serialQueue.async {...}

<块引用>

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

闭包内的第一行是

semaphore.wait()

所以闭包的执行被停止,等待信号量的绿灯.

<块引用>

这发生在不同的队列(不是主队列)上,所以我们不会阻塞主线程.

func producer() {DispatchQueue.global().asyncAfter(deadline: .now() + 3) {storage = "你好世界!"semaphore.signal()}}

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

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

打印(存储)

游乐场

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

import PlaygroundSupport

并运行此行

PlaygroundPage.current.needsIndefineExecution = true

In Java, we can do something like this:

synchronized(a) {
    while(condition == false) {
        a.wait(time);
    }
    //critical section ...
    //do something
}

The above is a conditional synchronized block, that waits for a condition to become successful to execute a critical section.

When a.wait is executed (for say 100 ms), the thread exits critical section for that duration & some other critical section synchronized by object a executes, which makes condition true.

When the condition becomes successful, next time current thread enters the critical section and evaluates condition, loop exits and code executes.

Important points to note: 1. Multiple critical sections synchronized by same object. 2. A thread is not in critical section for only the duration of wait. Once wait comes out, the thread is in critical section again.

Is the below the proper way to do the same in Swift 4 using DispatchSemaphore?

while condition == false {
    semaphore1.wait(duration)
}
semaphore1.wait()
//execute critical section
semaphore1.signal()

The condition could get modified by the time we enter critical section.

So, we might have to do something like below to achieve the Java behavior. Is there a simpler way to do this in Swift?

while true {
    //lock
    if condition == false {
        //unlock
        //sleep for sometime to prevent frequent polling
        continue
    } else {
        //execute critical section
        //...
        //unlock
        break
    }
}

解决方案

Semaphores

You can solve this problem with a DispatchSemaphore.

Let's look at this code. Here we have a semaphore, storage property of type String? and a serial queue

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

Producer

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

Here we have a function that:

  1. Waits for 3 seconds
  2. Writes "Hello world" into storage
  3. Sends a signal through the semaphore

Consumer

func consumer() {
    serialQueue.async {
        semaphore.wait()
        print(storage)
    }
}

Here we have a function that

  1. Waits for a signal from the semaphore
  2. Prints the content of storage

Test

Now I'm going to run the consumer BEFORE the producer function

consumer()
producer()

Result

Optional("Hello world!")

How does it work?

func consumer() {
    serialQueue.async {
        semaphore.wait()
        print(storage)
    }
}

The body of the consumer() function is executed asynchronously into the serial queue.

serialQueue.async {
    ...
}

This is the equivalent of your synchronized(a). Infact, by definition, a serial queue will run one closure at the time.

The first line inside the closure is

semaphore.wait()

So the execution of the closure is stopped, waiting for the green light from the semaphore.

This is happening on a different queue (not the main one) so we are not blocking the main thread.

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

Now producer() is executed. It waits for 3 seconds on a queue different from the main one and then populates storageand send a signal via the semaphore.

Finally consumer() receives the signal and can run the last line

print(storage)

Playground

If you want to run this code in Playground remember to

import PlaygroundSupport

and to run this line

PlaygroundPage.current.needsIndefiniteExecution = true

这篇关于我们如何在 Swift 中实现等待/通知的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆