Swift 的写时复制线程安全吗?

Chr*_*rdt 5 multithreading copy-on-write 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?
}
Run Code Online (Sandbox Code Playgroud)

Chr*_*rdt 0

好吧,既然 Apple/Swift Inc 没有人回复,我就大胆猜测一下:

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

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

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

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