(When) should `ManagedAtomic`/`UnsafeAtomic` be marked `Sendable`?

I just filed issue #45, asking UnsafeAtomic, ManagedAtomic and friends to be marked Sendable, reflecting that they are safe to transfer across concurrency domains.

I plan to do this the following way:

#if compiler(>=5.5) && canImport(_Concurrency)
extension UnsafeAtomic: @unchecked Sendable where Value: Sendable {}
extension ManagedAtomic: @unchecked Sendable where Value: Sendable {}

extension UnsafeAtomicLazyReference: @unchecked Sendable where Instance: Sendable {}
extension ManagedAtomicLazyReference: @unchecked Sendable where Instance: Sendable {}
#endif

Is this a good idea?

Is there a reason not to do this?

What exactly would break if atomic values weren't Sendable?

I assume that in most use cases, atomics values are used as mere components of other types (typically classes), whose sendability would need to be explicitly marked anyway -- nobody should be relying on Sendable inference for concurrent data structures.

On the other hand, I can imagine people passing around, say, a ManagedAtomic<Int> to implement a concurrent counter -- it seems reasonable that this should be implicitly Sendable:

struct Foobar {
  var counter: ManagedAtomic<Int>
  var value: String = ""
} 

(Keep in mind that atomic strong references are a thing -- we can use them to build lock-free concurrent data structures.)

3 Likes

I think these atomic constructs are examples of types that don't implement "value semantics" but are still "sendable".

I think the managed versions are clearly Sendable.

The Unsafe versions are not as clear, because nothing in them controls the lifetime of the memory location they refer to. I’m not concerned about the semantics of using the type but about the requirement to manage the lifetime of the memory location.

I believe this is the same (or better) situation as with Unsafe(Mutable)(Buffer)Pointer, which are Sendable.

1 Like

Yes, but those may be revoked. UnsafePointer Sendable should be revoked

2 Likes

Of course, there is no doubt that they can be used correctly and productively in multithread/multiactor situation, but the construct that is marked Sendable should perhaps be at a higher level?

I'm not sure what you would do with Atomics if they weren't Sendable. where Value: Sendable seems like an adequate safeguard. I do think both Unsafe and Managed should be @unchecked Sendable.

If someone deliberately uses atomics and explicitly specifies too weak of an ordering, then I think they get the race condition that they asked for.

2 Likes

Amusingly, pointer sendability means that UnsafeAtomic implicitly became unconditionally Sendable in Swift 5.5.

This means that constraining its conformance to where Value == Sendable in a new release would technically be a source-breaking change, which can in theory only be done in a new major release.

1 Like

Would the canImport(_Concurrency) check fail, if/when concurrency is back-deployed?

Using #if compiler(>=5.5) && $Sendable might work, if the Features.def names are intended for external use.

The Sendable protocol doesn't have availability, I assume because @_marker protocols are a compile-time-only feature?

1 Like

Hm, that depends on the details of how that's done, but I would be surprised if it involved a different module name -- I expect it'd be done by putting a special version of libswift_Concurrency.dylib inside app bundles that gets loaded if there is no such library in the OS (i.e., like old stdlib binaries that ship in apps that deploy back to before the stdlib was part of the OS, but made more complicated because the implementations need to be different). [Note though that I know nothing, and I'm surprised at least once every day. :laughing:]

$Sendable doesn't test for the right thing, sadly -- it's testing a compiler feature, while what we need to ensure is that we are using a stdlib that defines Sendable. (For macOS, Xcode 13 ships with the Swift 5.5 compiler but the 5.4 stdlib, so its compiler is aware of this stuff, but its stdlib isn't.)

1 Like

Swift Atomics 1.0.2 is out now, correcting UnsafeAtomics Sendable conformance.

(ManagedAtomic will gain a similar conformance in a future minor release.)

3 Likes