func doSomething() -> Int {
var sum = 0
let increaseWork = DispatchWorkItem {
sum = sum + 100 //point 1
}
DispatchQueue.global().async(execute:increaseWork)
increaseWork.wait()
return sum //point 2
}
Thread Sanitizer is saying that there is race condition between point 1 and point 2. But I don't think there is any race condition as increaseWork.wait() is blocking call and it will not pass until the closure is executed.
There could be a race condition between those 2 points. Imagine what happens if you execute the doSomething()
function on 2 separate threads like this:
increaseWork()
closure and finishes it. It's at the line with wait right nowAt this point, you can't tell for sure what is executed first: the sum = sum + 100
from the second thread or the return sum
from the first one.
The idea is that sum
is a shared resource which is not synchronised, so, in theory, that could be a race condition. Even if you took care that such thing does not happen, the Thread Sanitizer detects a possible race condition as it does not know whether you start a single thread or you execute doSomething()
function from 100 different threads at the same time.
UPDATE:
As I missed the fact that the sum
variable is local, the above explanation does not answer the current question. The scenario described would never take place in the given piece of code.
But, even though the sum
is a local variable, due to the fact it is used and retained inside a closure, it will be allocated on heap, rather than on stack. That's because the Swift compiler cannot determine whether the closure will be finished its execution before the doSomething()
function return or not.
Why? Because the closure is passed to a constructor which behaves like an @escaping
parameter. It implies that there is no guarantee when the closure will be executed, thus all the variables retained by the closure must be allocated on heap for safety. Not knowing when the closure will be executed, the Thread Sanitizer cannot determine that the return sum
statement will be indeed executed after the closure finishes.
So even though here we can be sure that no race condition can happen, the Thread Sanitizer raises an alarm, as it cannot determine it cannot happen.