Reputation:
I am trying to simulate a race condition by allowing multiple threads to read and write a shared state. But somehow in the end the result is correct. Below is the code i am using to simulate the behavior.
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)")
}
Output is : Done incrementing final value is 200
The question is how the final output is 200 when multiple threads are reading and writing a single value?
Upvotes: 0
Views: 837
Reputation: 154593
This may not happen in a Playground. Try running it in a real app.
The only way the two threads could interfere with each other is if one thread reads the value of val
between the time the other thread reads the value and increments it. You are likely just getting lucky as the time between reading val
and writing it with the incremented value is really tiny. Separate the reading and writing and introduce a delay (with usleep
) and you will see the race condition:
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()
Upvotes: 1