user4527951
user4527951

Reputation:

Race condition using GCD in swift

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

Answers (1)

vacawama
vacawama

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

Related Questions