取消初始化是否被视为“无数据竞争”?

Cou*_*per 6 concurrency race-condition memory-barriers swift swift3

在 Swift 中,类和结构的成员将被编译器生成的函数取消初始化(销毁)。

当不再有强引用时,对象将自动销毁。在最后一个强引用不再存在的任何线程上,该对象将在该线程上被销毁。这将销毁其所有结构成员,并可能销毁其成员对象,如果这也是最后一个强引用。

struct 类型的值将在其作用域停止退出后自动销毁。也就是说,无论发生这种情况的线程,该线程都会执行结构值的取消初始化。

我想知道这种取消初始化是否已受到保护以防止数据竞争。我的第一个猜测是,事实并非如此。但是,当它不是,怎么会一个插入时,由编译器生成这些成员变量的反初始化适当的同步原语当有潜在的数据竞争?

我将用一个例子来说明这个问题:

public class Foo {
    private let _syncQueue = DispatchQueue(label: "sync-queue", attributes: .serial)

    private var _array: [String] = [] 

    init() {
    }

    deinit {
    }

    func add(_ s: String) {
        _syncQueue.async {
            self._array.append(s)
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

这只是一个类,其实例可以从任何线程使用,并且调用该add(_:)方法是线程安全的。因此,在任何情况下,类型对象的使用Foo都应该是线程安全的。是真的吗?

好吧,如果取消初始化不同步,那么它不是!

当有一个最后的强引用生活中的一个线索是不是在以前的访问已经取得了同一个线程的问题,实现其利用同步原语(例如派遣LIB)和森林论坛的主题恰好可以不通过一些与此其他线程同步其他不相关的操作。

我能够真正产生这些数据的比赛,然后在出现的deinit方法Foo。找到发生这种情况的某些使用场景实际上并不容易,更糟糕的是,它们并不总是发生在同一场景中(取决于 GCD 产生的当前线程)。但最终它发生了,在 Xcode 8 beta 中新的 Thread Sanitizer 的帮助下,我实际上检测到了这些。

但我仍然想知道,在当前的 Swift 语言中,这是否被视为“按预期运行”,或者这是否实际上是一个错误。

如果 Swift 将使用一些与任何线程同步并在值的取消初始化之前使用的全局栅栏,则情况会是后者,但对于某些错误和在某些情况下,它会意外地不被使用。