Swift COW 线程安全

4
我正在了解Swift中的写时复制(Copy-On-Write)是如何工作的。但是,我对isKnownUniquelyReferenced 文档有些困惑,特别是这部分内容:

如果传递给object的实例同时被多个线程访问,则此函数仍可能返回true。因此,您必须仅从具有适当线程同步的可变方法中调用此函数。这将确保isKnownUniquelyReferenced(_:)仅在真正存在一个访问者或存在竞争条件(这已经是未定义行为)时返回true。

所以,请想象以下情况:

  1. 我们有一个没有内部同步的COW结构。
  2. 拥有该结构实例并使用锁进行保护的类
  3. 此结构的getter
  4. 并且想要安全地从getter线程返回此副本

import Foundation

class StorageBuffer {
    var field: Int = 1

    init(_ field: Int) {
        self.field = field
    }

    func copy() -> StorageBuffer {
        return StorageBuffer(field)
    }
}

struct Storage {
    private var _buffer = StorageBuffer(1)

    var field: Int {
        get {
            return _buffer.field
        }
        set {
            if !isKnownUniquelyReferenced(&_buffer) {
                _buffer = _buffer.copy()
            }

            _buffer.field = newValue
        }
    }
}

class StorageAware {
    private var _storage = Storage()
    private let _storageGuard = NSLock()

    var storage: Storage {
        _storageGuard.lock()
        defer {
            _storageGuard.unlock()
        }

        return _storage
    }
}

由于真正的复制将在后面进行。同步getter是否足够?在这种情况下,结构体本身是否是线程安全的,还是说需要同步setter?有没有关于Swift线程安全的完整文档?

1个回答

1
CoW结构体与Int一样线程安全,即它们不是原子的。因此,就像在修改Int时需要锁定并发访问一样,您也需要锁定并发访问CoW结构体。
lock.lock()
var myInt = _storedInt // lock required, not an atomic op
lock.unlock()
myInt += 1

复制 CoW 结构时,您需要执行相同的操作(尽管您没有展示您的 _storage 是否被修改过,但它被标记为 var,所以这表明它被修改过 - 您需要锁定对 _storage 的写入访问)。

然而,当您执行此操作时,isKnownUniquelyReferenced 保证在引用唯一时返回 true。

错误:

var myStorage = _storage // this can race
myStorage.value = 10

正确:

lock()
var myStorage = _storage // properly locked, can't race
unlock()
myStorage.value = 10 // this is safe now

错误版本显示了文档所讨论的比赛。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接