迭代时从数组中删除项目的安全方法?

时间:2018-02-09 15:11:51

标签: arrays swift algorithm thread-safety swift4

我想要执行一系列闭包,并以安全的方式删除每个项目。

如果我这样做:

array.forEach { $0() }
array.removeAll()

项目可能在forEachremoveAll执行之间偷偷摸摸,所以我可能会移除一个在前一行中没有执行的元素

这样的事情会更安全吗?

extension Array {

    mutating func removeEach(handler: @escaping (Element) -> Void) {
        enumerated().forEach { handler(remove(at: $0.offset)) }
    }
}

有没有一种安全的方法以算法的方式执行此操作而不是使用线程锁?

1 个答案:

答案 0 :(得分:5)

首先,我假设array这里是一个属性(否则这个问题没有多大意义)。其次,我假设array已经成为线程安全的。也许是这样的,它提供了阵列级别的同步访问。

class Container {
    let arrayQueue = DispatchQueue(label: "arrayQueue", attributes: .concurrent)
    var _array: [() -> Void] = []
    var array: [() -> Void] {
        get {
            return arrayQueue.sync { return _array }
        }
        set {
            arrayQueue.async(flags: .barrier) {
                self._array = newValue
            }
        }
    }
}

使用这种系统,你可以创建一个清除数组的原子执行器:

func execute() {
    arrayQueue.async(flags: .barrier) {
        // Make a local copy of the array
        let toExecute = self._array

        // Clear the array (we have a barrier, so there's no race condition)
        self._array.removeAll()

        // async to another queue to avoid blocking access while executing
        DispatchQueue.global().async {
            for closure in toExecute {
                closure()
            }
        }
    }
}

(你提到过#34;没有使用线程锁。"你几乎不应该在Swift中使用线程锁。这就是GCD的用途,它做了很多工作来避免锁定所以你不必这样做。如果你的目标是在不使用GCD的情况下这样做,那么不,没有某种并发系统就没有办法从多个线程安全地改变一个属性,并且最好的并发系统斯威夫特是GCD。)