Memory Orderings (LLO Archive)
Created 2025-11-30, last modified 2025-11-30
Part of my archive of Layover Linux Official posts on Tumblr.
2025-08-13
I'm finally starting to get my head around memory orderings in C++, but it's mainly serving to make me pissed off. No wonder people think concurrency is hard. It's normally not actually that hard to get concurrency right on a purely hardware model, but with an optimizing compiler reordering instructions basically at will, you get a whole extra layer of fuckery that you have to tame by asking nicely. And actually you have to ask nicely in 2+ separate places symmetrically for acquire vs release.
While I'm pretty far out from multithreading support in Prone, this is making me glad I'm committing to a bunch of architectural decisions that will make threading a lot simpler to do correctly.
- Most of the data you deal with has "copy-on-write across function boundaries" semantics. It's as if you get all your arguments passed as immutable, but transparently make a local copy when you edit it.
- Under the hood, this usually uses a safe kind of reference, so you get reference performance but value semantics.
- Reference types exist, but work differently. Their internals are private, and you can only interact with them through function calls written in native code. This allows them to uphold more complex invariants, especially re thread safety, at the expense of the flexibility and transparency of data objects.
- The most common type of reference is just a boxed data object, where loads and stores are an explicit API. So when you load, you're getting an immutable snapshot with COW semantics, held alive by reference count as long as you need it, regardless of whether the box value gets replaced after your load.
So we'll see if I have to do anything crazy to avoid maladaptive compiler optimizations, but I think that's good groundwork to minimize the surface area for headaches.

