deinitialization被认为是“数据竞争免费”吗?

时间:2016-06-24 08:04:17

标签: swift concurrency race-condition memory-barriers swift3

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

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

类型struct的值将在其范围停止退出后自动销毁。也就是说,无论发生什么线程,这个线程都会执行struct值的取消初始化。

我想知道这种取消初始化是否已经受到数据竞争的保护。我的第一个猜测是,它不是。但是当它不存在时,当有潜在的数据竞争时,当编译器 AND 生成这些成员变量的去初始化时,如何会插入正确的同步原语吗?

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

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)
        }
    }

}

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

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

问题意识到当一个线程中存在最后一个强引用时,该线程与使用同步原语的先前访问的线程不同(例如,dispatch lib)和iff此线程发生通过其他一些不相关的操作与其他线程不同步。

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

但是我仍然想知道,在目前的Swift语言中,这是否被视为“表现得如预期”或者这是否真的是一个错误。

如果Swift使用一些与任何线程同步的全局fence并且在取消初始化值之前使用,那么后者就是这种情况,但对于某些bug而言,在某些情况下它会被意外地使用。

0 个答案:

没有答案