在快速使用GCD的比赛条件

时间:2018-06-04 11:46:38

标签: swift grand-central-dispatch

我试图通过允许多个线程读取和写入共享状态来模拟竞争条件。但不知何故,最终结果是正确的。下面是我用来模拟行为的代码。

import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

let queue = DispatchQueue(label: "my-queue", qos: .userInitiated, attributes: [.concurrent, .initiallyInactive])
var val = 0
let group = DispatchGroup()
group.enter()
queue.async {
    for _ in 0..<100 {
        val += 1
    }
    group.leave()
}

group.enter()
queue.async {
    for _ in 0..<100 {
        val += 1
    }
    group.leave()
}

queue.activate()

group.notify(queue: DispatchQueue.main) {
    print("Done incrementing final value is \(val)")
}
  

输出为:完成递增的最终值为200

问题是当多个线程正在读取和写入单个值时,最终输出是200?

1 个答案:

答案 0 :(得分:1)

这可能不会在游乐场发生。尝试在真实的应用程序中运行它。

两个线程互相干扰的唯一方法是,如果一个线程在另一个线程读取值并增加它之间读取val的值。你可能只是幸运,因为阅读val和用递增值写的时间之间的时间非常小。将阅读和写作分开并引入延迟(使用usleep),您将看到竞争条件:

let queue = DispatchQueue(label: "my-queue", qos: .userInitiated, attributes: [.concurrent, .initiallyInactive])
var val = 0
let group = DispatchGroup()
group.enter()
queue.async {
    for _ in 0..<100 {
        let value = val
        usleep(10_000)
        val = value + 1
        print("val = \(val)")
    }
    group.leave()
}

group.enter()
queue.async {
    for _ in 0..<100 {
        let value = val
        usleep(9_000)
        val = value + 1
        print("val = \(val)")
    }

    group.leave()
}

queue.activate()