DEV Community

Šimon Kručinin
Šimon Kručinin

Posted on • Originally published at easyblunders.wordpress.com on

Atomic sync blocks in Swift

We will access state from different threads synchronously and do it in a safe manner. That must be easy!

When considering concurrent access to data (a.k.a. state, a.k.a. variables) in Swift, from different threads, the usual practice is to use Structured Concurrency or Grand Central Dispatch (Dispatch Queue, anyone?). Combine and other reactive frameworks also provide support. But there’s a catch. These are all asynchronous APIs, meaning that if I call it now, I’ll get results sometimes later. What if I need the result now and continue some logic based on it? What if I don’t use async/await tasks everywhere yet?

Well, Dispatch Queues have also .sync() method, but from experience it’s best to avoid it. We don’t always have the luxury of knowing which Dispatch Queue we’re currently running on and calling .sync() on the same queue is a certain death (or deadlock).

Certainly, the code can and should be restructured to run asynchronously if thread safety is needed. We should rewrite our codebases towards modern approaches. Rainbows and unicorns await those who always do all the right things. Using Structured Concurrency or GCD is still the best practice, no doubt about it. But sometimes we just need that sync block in our test or a routine already running in background and we’re willing to wait for it. Can we make it happen, please?

Yes, we have OSAllocateUnfairLock (iOS 16+) or NSRecursiveLock (iOS 2+) at our disposal. Use them as mutexes to guard a critical section:

let myLock = OSAllocatedUnfairLock()
myLock.withLock {
    consistentState1 = "Some"
    consistentState2 = "information"
}
Enter fullscreen mode Exit fullscreen mode
import Foundation

let myLock = NSRecursiveLock()

func changeState1(_ value: String) {
    myLock.lock()
    consistentState1 = value
    myLock.unlock()
}

myLock.lock()
changeState1("Some")
consistentState2 = "information"
myLock.unlock()

Enter fullscreen mode Exit fullscreen mode

Also, there’s a great summary of available thread safety tools by SwiftRocks.

Top comments (0)