DispatchGroup和可能的竞争条件?

时间:2017-05-03 20:53:58

标签: swift

以下是否会产生可能的竞争条件?

let syncGroup = DispatchGroup()
var tempData: [Int]
for index in 1...10 {
      syncGroup.enter()
      // Alamofire is being called in the following. 
      // I am leaving out implementation, just to simplify.
      asyncTaskUsingAlamofire(completionHandler: { (data: [Data]) in
         // Possible race condition?
         // Should I use something like `sync()` and how?
         tempData.append(data)
         syncGroup.leave()
      })
}
syncGroup.notify(queue: .main) {
// We can go on, all data is added to tempData
}

我可以看到swift有一个sync()如果你怎么解决这个问题?

2 个答案:

答案 0 :(得分:3)

串行队列

Sulthan's answer非常相似,我通常会在此方案中使用custom serial queue

let group = DispatchGroup()
var results = [Int]()
let serialQueue = DispatchQueue(label: "serialQueue")

for _ in 1...10 {
    group.enter()
    asyncTaskUsingAlamofire { data in
        serialQueue.async {
            // Multiple instances of this block will be executed into a serial queue
            // So max 1 block at a time
            // This means results is accessed safely
            results.append(contentsOf: data)
            group.leave()
        }
    }
}

group.notify(queue: .main) {
    print(results)
}

results数组是安全访问的,因为每个变异块的实例都是

results.append(contentsOf: data)
group.leave()

在串行队列中执行。

serialQueue.async {
    results.append(contentsOf: data)
    group.leave()
}

换句话说,阻止的10个实例已排入serialQueue并一次执行

这确保了results的安全访问。

答案 1 :(得分:1)

您应确保在同一队列中调用所有完成处理程序。如果未在同一队列中调用它们,则可以同时调用它们,从而创建竞争条件。

如果您不确定是否在特定队列上调用了完成处理程序,则只需插入.async包装器:

asyncTaskUsingAlamofire(completionHandler: { (data: [Data]) in
    DispatchQueue.main.async {
        tempData.append(data)
        syncGroup.leave()
    }
}

但是,Alamofire总是在main队列上执行回调,因此不会出现竞争条件且您的解决方案是安全的。