首页 > 解决方案 > Swift 的写时复制线程安全吗?

问题描述

根据定义使数组或字典成为值类型,但实际上仅在对其的引用尝试修改它时才复制它是一个可爱的想法,但它让我在多队列/线程上下文中保持警惕。我需要知道:

Swift 的写时复制功能是线程安全的吗?例如:如果我在一个队列上创建一个数组并将其传递给另一个队列,那么任何一个队列都可以安全地修改它,而另一个队列可能正在读取或修改它吗?既然按照定义,当数组引用被传递到第二个队列时,就会进行复制,我们是否可以假设 Swift 工程师做了正确的事情并以队列安全的方式实现了写时复制?

我发现了这个旧的讨论,这似乎是权威的,但在两个方向上! https://developer.apple.com/forums/thread/53488

一些可信的声音说它是线程安全的,其他人说它不是。我想这可能是因为在 Swift 的某些早期版本中不是这样,而在 Swift 5 中可能是这样。这里有人肯定知道 Swift 5 吗?

下面是一些示例代码来说明这个问题:

func func1()
{
    var strings1: [String] = ["A", "B", "C"]
    var strings2: [String] = strings1   // array not actually copied
    queue.async()
    {
        strings2.append("D")
    }

    print(strings1[0])    // is this reference thread-safe?
    strings1.append("E")  // is this modification thread-safe?
}

标签: swiftmultithreadingcopy-on-write

解决方案


好的,由于没有来自 Apple/Swift Inc 的人回复,我会冒险做出最好的猜测:

我想当你在 swift 中有一个 Array 值时,它是对 NSArray 或 NSMutableArray 的引用的引用。(是的,我知道这仅适用于类对象,但让我们在这里保持简单。)无需为您的 Array 值分配新值,可以通过简单的方式使较低级别的引用引用不同的 NS 对象对其进行的操作,例如追加或修剪。还有一个附加到底层 NS 对象的引用计数。

当你修改一个数组时,Swift 做的第一件事就是检查 Swift 引用是否是底层 NS 对象的唯一引用。如果是这样,则在必要时将 NSArray 转换为 NSMutableArray 并进行修改。如果不是,则将 NSArray 复制到 NSMutableArray 中,进行修改,并将较低级别的 Swift 引用更改为指向新的 NS 对象。

如果这确实是 Copy on Write 遵循的过程,并且如果我们可以假设引用计数机制和保留/释放系统是线程安全的,那么我会说 Copy on Write 是线程安全的。即使另一个线程正在进行修改,如上所述,因为它正在修改 IT 刚刚制作的副本,它根本不应该改变原始数组。

如果您确定我写的任何内容都不正确,或者您知道与此问题相关的其他信息,请在此处分享。这个问题太重要了,不能留给“它应该只是工作”的状态。:-)


推荐阅读