Search code examples
swiftactorswift-concurrencythread-sanitizer

Data race occurring in Swift Actor


I found a data race in my Swift app by using the Thread Sanitizer, and so I made my first attempt to fix race conditions by converting the offending class to an actor. The crash that the race was causing seems to have gone away, but Thread Sanitizer is still saying there's a data race in the code, which I thought should be impossible in the actor.

I can't post the entire actor here, but here is the code where the race is occurring:

actor SampleActor {
    private var things = Set<Int>()
    
    func addThing(_ newThing: Int, seconds: Double) {
        things.insert(newThing)
        Task {
            try await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000))
            self.things.remove(newThing)
        }
    }
}

// Code to cause the race
let sample = SampleActor()
for n in 0 ..< 1000 {
    Task {
        await sample.addThing(n, seconds: Double.random(in: 0...1.0))
    }
}


I'm probably going about this the wrong way, but I need to add an object to the SampleActor's set of objects, and have it be automatically removed after some amount of time.

Is there a better way to do this? And what am I missing about the use of actor to avoid the data race in this case? Shouldn't SampleActor.things be immune to races here because it's a property of an actor?


Solution

  • Remove the Task { part in the actor

    Add async to the function

    func addThing(_ newThing: Int, seconds: Double) async {