No Built-In AsyncLock in Swift? No atomic actor functions?

This amazing structure called an actor in Swift, which is supposed to free us from all evils of concurrency, does not actually do so because it can still be re-entered by multiple execution paths between awaits (correct me if I’m wrong).

When trying to ensure thread safety in an actor, how can someone create an atomic function or lock an actor’s function?

It seems like I have to implement my own AsyncLock, which also needs to be an actor itself to synchronize its state. However, that means I cannot use defer to unlock because it requires awaiting, so I’d have to use a callback block instead. On top of that, I also need to ensure that the input and output of the locked area are Sendable within my actor. It’s just insane.

Does anyone have a reasonable way to create an atomic function within an actor?

1 Like

You are right, there is no built-in AsyncLock.

And yes, you can implement one with an actor. But that is problematic for the reasons you describe. So usually these are built using other thread-safety mechanisms.

There are a number of open source libraries that implement constructs like this, which might be a nice option if you aren't interested in building one yourself.

You can also do what I've come to call "continuation juggling", to deal with reentrancy. Some lock implementations work this way internally. I find it pretty hard to do, so I tend to avoid it and just use a library though.

1 Like