Swift COW 线程安全

Posted

技术标签:

【中文标题】Swift COW 线程安全【英文标题】:Swift COW thread safety 【发布时间】:2017-12-13 21:52:58 【问题描述】:

我正在研究写时复制在 swift 中的工作方式。 isKnownUniquelyReferenced documentation 有点困惑。特别是本节:

如果作为对象传递的实例同时被多个线程访问,该函数可能仍然返回 true。因此,您只能从具有适当线程同步的变异方法中调用此函数。这将确保 isKnownUniquelyReferenced(_:) 仅在确实有一个访问器或存在竞争条件时才返回 true,这已经是未定义的行为。

所以想象一下。

    我们有内部没有同步的 COW 结构。 拥有此结构实例并用锁保护它的类 此结构的吸气剂 并希望安全地从此 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就够了吗?在这种情况下,是否有必要或结构本身是线程安全的? 是否有任何关于 swift 线程安全的完整文档?

【问题讨论】:

【参考方案1】:

CoW 结构与Int 一样是线程安全的,即它们不是原子的。因此,就像您在修改 Int 时必须锁定并发访问一样,例如

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

错误的版本显示了文档所谈论的种族。

【讨论】:

以上是关于Swift COW 线程安全的主要内容,如果未能解决你的问题,请参考以下文章

Swift - 分派到主队列是不是足以使 var 线程安全?

如何使 Swift 类单例实例线程安全?

将 Swift 调用同步到基于 C 的线程不安全库

swift 线程安全访问数组的开始。

Swift - 检查弱变量是不是为 nil 或不是线程安全的?

swift实现线程安全的栈和队列