对于SWIFT中的读者-写入者问题,我似乎有一个classic 的解决方案:使用具有写障碍的并发DispatchQueue.然而,当我运行测试代码时,它死机了.

下面是我想成为线程安全的数据 struct :

class Container<T> {
    private var _value: T
    private let _queue = DispatchQueue(label: "containerQueue", attributes: .concurrent)
    
    init(_ value: T) {
        self._value = value
    }
    
    var value: T {
        get {
            _queue.sync {
                _value
            }
        }
        set {
            _queue.async(flags: .barrier) {
                self._value = newValue
            }
        }
    }
}

下面是我的测试代码:

class ContainerTest {
    let testQueue = DispatchQueue(label: "testQueue", attributes: .concurrent)
    var container = Container(0)
    let group = DispatchGroup()
    
    func runTest() {
        for i in 0..<1000 {
            testQueue.async(group: group) {
                self.container.value = max(i, self.container.value)
            }
        }
        
        group.notify(queue: .main) {
            print("Finished")
        }
    }
}

重复运行的代码片段只是一些随机的读写操作.它并没有试图产生任何合理的东西,它只是在那里对数据 struct 进行压力测试.

因此,当我运行此命令时,不会打印"完成".但是,如果我将_queue.async(flags: .barrier)更改为_queue.sync(flags: .barrier),那么我会看到"Finish"打印出来.

我猜,当我使用async写入版本时,我会遇到死锁,但为什么呢?这是通常使用的教科书读者-作者解决方案.也许是我的测试代码有问题,但是,为什么呢?

推荐答案

几乎可以肯定的是,您正在耗尽线程池.这是苹果工程师反复警告不要使用的一种模式,因为这种风险(我知道它在许多地方也被记录为一种常见模式).每次对.async的调用都会产生一个线程,如果出现严重的争用(如您正在创建的那样),最终将没有可用的线程,并且一切都将锁定.

在现代的Swift ,这方面的正确工具是演员.在前并发Swift中,您可能希望使用OSAllocatedUnairLock,但是当您发现自己创建了一个原子属性时,您认为您的意思是线程安全,you are often on the wrong road.

Swift相关问答推荐

Swift Tree实现中的弱var

ARRaycast Query和前置摄像头(ARFaceTrackingConfiguration)

当计数大于索引时,索引超出范围崩溃

为什么自定义串行队列的目标是全局队列时,Swift中不会并发执行?

从 Obj-C 函数返回 swift 类的不兼容指针类型

在这个使用 URLSession 的简单 case 中是否创建了一个强引用循环?

在领域 SwiftUI 异常中使用 Apple 登录:无法识别的 Select 器发送到实例

我如何读取并通知可可 macos 中某个类的计算(computed)属性?

如何将变量添加到不属于可解码部分的 struct ?

Swift // Sprite Kit:类别位掩码限制

当使用 CGFloat 而不是数字文字时,为什么 node 的位置会发生变化?

按钮图像不会立即刷新

单击按钮后的计时器发布者初始化计时器

ZStack 中的 ProgressView 与 View 的行为不同

在 Swift 中,如何查看 Process() 传递给 shell 的字符串?

Xcode swift ui 错误KeyPathComparator仅在 macOS 12.0 或更高版本中可用

swift 如何从 Int 转换?到字符串

Swift 中的 CommonHMAC

如何在 SwiftUI 中创建带有图像的按钮?

Objective-C 方法与可选需求方法 Swift 冲突