Introducing Swift Atomics

Swift Atomics, "a new open source package that enables direct use of low-level atomic operations in Swift code", is now available:

Please feel free to ask questions about the post here!

CC @lorentey @kylemacomber

32 Likes

Might it be valuable to discuss when using atomics instead of explicit locks might be appropriate? Given that ManagedAtomic is far more approachable than the C-based atomics we had access to before, it might be to explain when Swift developers would use one or the other.

While Swift doesn't have a native lock API, you aren't limited to importing locks from C: the Dispatch and Foundation libraries already provide excellent synchronization tools! These are essentially the best we could reasonably provide in Swift today.*

* UnsafeAtomic/ManagedAtomic-style convenience wrappers for additional, platform-specific, synchronization constructs could perhaps find a home in the recently announced Swift System project. But I find Dispatch already provides great solutions for most use cases.

I'd never use atomics unless the situation positively forced my hand to do it. :wink: In almost all cases, straightforward synchronization using serial dispatch queues or locks is far, far easier to get right than trying to deal with atomics. And in almost all cases, the resulting code performs great.

If you have a problem that is solvable with higher-level synchronization, then going with that is invariably the right approach: it saves immense amounts of effort that would be spent on debugging subtle concurrency issues. (And all that effort would be inevitably repeated whenever the code is modified in any way.)

Of course, locking isn't always appropriate. It is incomparably more difficult to write even the most rudimentary lock-free queue data structure than a locking one, but if you're trying to implement something like the Dispatch framework in pure Swift, then you don't really have a choice -- you must embrace atomics. Thankfully, these situations are few and far between; but Swift cannot truly be a systems programming language unless you can use it to solve these sorts of problems, too!

11 Likes

Congrats! Great job!

Suggestions of improvement to the Announcement page on Swift.org:

  1. The announcement goes to lengths disencouraging (misusing) Atomics due to error prone etc, for the sake of safety, which is all well. However, it does not give a single example on when a user would need to use the Package. The snippet code of a counter does not convey a usecase. Maybe you could come up with one example?
  2. You mention using a “Thread Sanitizer” for asserting correctness when using Atomics - what is that? Some instruments tool?
3 Likes

It is an LLVM tool. You can learn more about the available sanitizers, as well as how to enable them in Xcode and the command-line, here: Diagnosing memory, thread, and crash issues early | Apple Developer Documentation

4 Likes

What Karl said.

For a nice intro to TSan, I would also watch Anna's WWDC talk from 2016: WWDC16 - Videos - Apple Developer

When someone complains about a bug that occurs infrequently and they can't reproduce it, more often than not simply clicking the "Thread Sanitizer" box immediately reveals the problem.

6 Likes

Been an iOS dev for 7 years and Swift dev for 6 years - and I’ve completely missed this :smile: wow, will definitely check it out, thanks!

Congrats for the achievement.

This will be very handy in my case, given i have a thread scheduler/pool implementation that defaults to pthread, and was using the rather nice atomic interfaces from the borrowed "Atomics.swift" from the Swift NIO project.

Time to update that..

PS: The only thing missing in Swift now, to become a heavy-weight champion, is to make that sweet ownership manifesto come true.

4 Likes

Yupp Variadic Generics and Ownership - then my life is complete.

Simple rule of thumb: Never use "low-level" atomic and always use explicit locks.

As ManagedAtomic is considered a low-level API, avoid it as much as possible. This is not a locking primitive, and should not be use as one. It may be useful for an atomic counter though.

C based API like pthread_mutex_t are extremely fast when there is no contention as they are using a simple atomic CAS as fast path. If you think this is still too heavy for your need, consider something like unfair lock API. But never try to rewrite synchronisation primitive unless you really know what you're doing.

2 Likes

Congrats