Home > other >  Why does DispatchQue.sync cause Data race?
Why does DispatchQue.sync cause Data race?

Time:01-05

Based on my printed output in the console window, the work in que2 was only executed after the que1 fully finished its work, so my question is why did I get the Data race warning even though the first block of work in que1 was completely synchronous?

Data race in closure #2 () -> () in BlankSwift at BlankSwift.porsche : BlankSwift.Car

struct Car {
 var name: String
}

let que1 = DispatchQueue(label: "que1", qos: .background)
let que2 = DispatchQueue(label: "que2", qos: .userInteractive)

var porsche = Car(name: "Porsche")

for i in 0...100 {
 que1.sync {
    porsche.name = "porsche1"
    print(porsche.name)
    porsche.name = "Porsche11"
    print(porsche.name)
    if i == 100 { print("returned ")}
 }

 que2.async {
    porsche.name = "porsche2"
    print(porsche.name)
    porsche.name = "Porsche22"
    print(porsche.name)
 }
}

CodePudding user response:

While que1.sync is indeed called synchronously, que2.async is asynchronous on a different queue, so it schedules it's closure and immediately returns, at which point you go to the next iteration of the loop.

There is some latency before the que2 closure begins executing. So for example, the closure for que2.async that was scheduled for iteration 0, is likely to start executing while que1.sync is executing for some later iteration, let's say iteration 10.

Not only that que2 may well have multiple tasks queued up before the first one begins. Since it's a serial queue (you didn't specify the .concurrent attribute) you don't have to worry about que2 tasks racing on other que2 closure access of porsche.name , but they definitely can race on que1 closure accesses.

As for output ordering, ultimately the output will go FileHandle.standarOutput to which the OS has a buffer attached, and you don't know what kind of synchronization scheme the OS uses to order writes to the that buffer. It may well use it's own call to DispatchQueue.async to ensure that I/O is done in a sensible way, much the way UI updates on AppKit/UIKit have to be done on the main thread.

  • Related