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

Tru*_*an1 1 arrays algorithm thread-safety swift swift4

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

如果我只是这样做:

array.forEach { $0() }
array.removeAll()
Run Code Online (Sandbox Code Playgroud)

项目可能在执行forEach和removeAll执行之间偷偷摸摸,所以我可能会删除在前一行中没有执行的元素.

这样的事情会更安全吗?

extension Array {

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

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

Rob*_*ier 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
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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()
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

(你提到"没有使用线程锁."你几乎不应该在Swift中使用线程锁.这就是GCD的用途,它做了很多工作来避免锁定所以你没有必要.如果你的目标是不使用GCD就可以做到这一点,那么不,没有某种并发系统就没有办法从多个线程安全地改变一个属性,并且Swift的最佳并发系统是GCD.)