Static property is not concurrency-safe: Is there an easy solution?

Currently I rework my projects for Swift 6.
Now I have an error

Static property 'wName' is not concurrency-safe because it is nonisolated global shared mutable state

I'm not sure how to solve this issue without a complete rework of the application structure. It is a command line app where the main code calls

    MBackup.doSomething(…)
    …
    MBackup.cleanUp(…)

and the class is defined in this way

class MBackup : BackupBase {
    static var wName : String?

    class func doSomething(…) -> Bool {
         // initialize all
         self.Name     = getName(…)
        // do some work
    }

    class func cleanUp(…) {
      // use/access wName
}

Do I miss something to get an easy concurrency-safe way to solve this issue?

Static mutable properties are generally not safe because they can be concurrently modified from any thread/actor, and this is what the compiler error is trying to communitate. There are multiple ways to fix this:

  • If you don't even need to write to wName, make it a static let instead of static var.
  • If you still need to mutate it occasionally, wrap it into a Mutex (the new concurrency primitive available in the Standard Library with Swift 6.0 and the newest Apple OS releases) or e.g. OSAllocatedUnfairLock for former Apple OS versions.
  • Make MBackup an actor, the static property will become isolated to it.
  • Constrain it to some global actor, perhaps alongside with the whole MBackup class that needs to access it. This way, all reads and writes to it will be serialized.
  • Make it nonisolated(unsafe). If it's only accessed from the MBackup class, and you can make sure by other means that all accesses are serialized, you can simply tell the compiler to ignore the concurrency-safety in this instance. It'd also help to perhaps make it private so that you don't accidentally access it from outside. This fix is typically the last resort, though.

The first two and the last options lean more in the direction of not requiring a complete app rework.

9 Likes

Also if you only use this static property from MainActor you can annotate it as @MainActor (or the whole type). If you are using it from different contexts (actors, queues, threads etc) than you had the problem all along and I would suggest following @nkbelov 's points

2 Likes

Well I need just to set the value in "doSomething“ but calculation is needed.
No idea how to solve this.

@MainActor did fix the error.

Now I look for different solutions as mentioned above ( Make MBackup an actor …)

Thanks for your help.

If I understand correctly, doSomething in your case is more like a one-time initialization rather than a repeated call. What you could do instead if program logic allows it is to initialize the value through a lazily evaluated closure instead (while converting the variable to a let):

static let wName : String? = {
    // some logic
    return name
}()
3 Likes

Exactly. I need to rethink my code to use a static let…

Thanks for giving the great solution. i find the answer.