Memory Models and Atomic Ordering — acquire/release/seq_cst TODO
Concept
As long as single-thread semantics are preserved, CPUs and compilers are free to reorder memory accesses, so what other threads see, and in what order, is governed by the memory model. A relaxed atomic operation only guarantees the atomicity of the operation itself, not its ordering relative to surrounding accesses. When a release store pairs with an acquire load that reads its value, a happens-before relationship is established: everything written before the release becomes visible to code after the acquire. seq_cst goes further and guarantees a single global order across all seq_cst operations, making it the most expensive. Go doesn't expose these ordering options directly — it describes its memory model in terms of the happens-before rules created by channels, mutexes, and sync/atomic.
Getting ordering wrong usually still passes on x86, and only shows up under a weaker memory model like ARM or under heavy load, which makes it an extremely hard-to-reproduce bug.
Code & Formula
# 메모리 모델과 원자성 순서 — release/acquire 페어링이 만드는 happens-before 관계를 흉내낸다.
# (Python 은 GIL 때문에 진짜 하드웨어 재배열은 안 보이지만, release-store -> acquire-load 짝짓기 패턴 자체는 동일하다.)
import threading
data = 0
ready = threading.Event() # release/acquire 짝을 흉내내는 신호: set()=release, wait()=acquire
observations = []
def writer():
global data
data = 42 # release 이전의 모든 쓰기는...
ready.set() # ...release. 이 시점 이후 acquire 한 쪽에는 반드시 42가 보여야 한다.
def reader():
ready.wait() # acquire: release 이전의 모든 쓰기가 happens-before 로 보장되어 보인다.
observations.append(data) # 만약 순서 보장이 없었다면(relaxed) 0을 볼 수도 있었다.
# seq_cst 라면 여기에 더해 "모든 스레드가 동의하는 단일 전역 순서"까지 보장하지만, 비용이 가장 크다.
runs_correct = 0
for _ in range(1000):
data = 0
ready.clear()
t_r = threading.Thread(target=reader)
t_w = threading.Thread(target=writer)
t_r.start(); t_w.start()
t_r.join(); t_w.join()
if observations[-1] == 42:
runs_correct += 1
print("total runs:", len(observations))
print("runs where acquire correctly saw release's write:", runs_correct)
print("release/acquire happens-before held every time:", runs_correct == len(observations))
docs/code/algorithms/algorithms-36.py
Exercise
Implement the classic flag/data variable pattern once with relaxed and once with release/acquire ordering, run it millions of times on an ARM-family device, and count how often the ordering appears reversed.
Practical Connection
This is the correctness basis for lock-free queues and shared-state flags in high-performance server code — for Verex's in-memory order book shared across multiple goroutines, it's the standard for judging where atomic operations suffice and where a mutex becomes necessary.
Where it lands in Jayverse
- Verex: document the memory ordering per shared field in the matching engine. For the in-memory order book, pick and write down the specific ordering (relaxed / acquire-release / seq_cst) per shared field, and add a stress test flagged for a weak-memory model rather than trusting x86-only test runs.
- Devnet/CI: make a race-detector run a required CI gate. Since ordering bugs pass on x86 and only surface under load or a weaker model, add the order-book concurrency tests under a race detector as a mandatory CI job, not optional.
- OFA: decide ordering for the solver's shared bid-collection state too. Treat the auction's shared bid state as the same class of hazard as Verex's order book; choose acquire/release vs mutex deliberately rather than assuming atomics are always cheaper.
Key expressions
| Expression | 뜻 · 쓰이는 자리 |
|---|---|
| as long as | ~하는 한, ~이기만 하면 · 단일 스레드 의미만 지켜지면 재배열이 허용됨 · "As long as single-thread semantics are preserved" |
| pair with | ~과 짝을 이루다 · release store와 acquire load가 짝지어질 때 관계가 성립함 · "a release store pairs with an acquire load" |
| happens-before | (일어난 후에 일어남을 보장하는) 선행 관계 · 두 연산 사이의 순서 보장을 나타내는 용어 · "a happens-before relationship is established" |
| go further | 한 단계 더 나아가다 · seq_cst가 다른 정렬 방식보다 더 강한 보장을 함 · "seq_cst goes further and guarantees a single global order" |
| show up | (문제가) 드러나다, 나타나다 · 약한 메모리 모델이나 고부하에서만 버그가 드러남 · "only shows up under a weaker memory model" |
| hard-to-reproduce | 재현하기 어려운 · 순서 오류 버그가 흔히 이런 성격을 가짐 · "an extremely hard-to-reproduce bug" |
| the standard for judging | 판단 기준 · 뮤텍스와 원자적 연산 중 어디를 써야 할지 가르는 기준 · "it's the standard for judging where atomic operations suffice" |
| ARM | ARM(Advanced RISC Machine) 아키텍처 · x86과 달리 약한 메모리 모델이라 정렬 버그가 여기서 드러남. "only shows up under a weaker memory model like ARM" |
| seq_cst | 순차적 일관성(sequentially consistent, seq_cst) · 모든 seq_cst 연산에 걸쳐 전역적으로 하나의 순서를 보장하는, 가장 비싼 정렬 수준. "seq_cst goes further and guarantees a single global order" |
| sync/atomic | sync/atomic · Go가 acquire/release 같은 명시적 옵션 대신 채널·뮤텍스와 함께 happens-before 규칙을 표현하는 패키지. "channels, mutexes, and sync/atomic" |
If you study this on a given day, add a note link and a ✅ to this line in the source curriculum (docs/knowledge/dev-100-curriculum.md) and this spot will lead straight to the note body. You can also write directly on this page — but regenerating overwrites it, so it's safer to keep anything you want to save as markdown under docs/algorithms/.