Async Mutexes

Dev says ‘no locks’… then reaches for a BIG lock; commenters scream hypocrisy

TLDR: A TigerBeetle dev admits single‑thread async might still lean on a big lock, sparking outrage. Commenters split: some say locks in single‑thread async are needless and the real danger is placing waits wrongly; others argue a single bouncer lock is the simplest way to keep chaos out.

A database dev behind TigerBeetle just confessed to a spicy contradiction: he’s spent years preaching that single‑threaded async systems don’t need locks, yet his compaction code keeps reaching for one giant “do not disturb” sign. Cue the comment section meltdown. The loudest voice? “Async mutexes are a red flag,” says pwnna, arguing that in single‑thread land everything is atomic until you hit an await—so the real problem is sprinkling waits where they don’t belong. Meanwhile, didibus gets tangled in the word soup: “Aren’t actors supposed to share nothing?” If there’s only one “actor,” is this just a fancy name for a big state machine with a single bouncer at the door? The peanut gallery escalates fast: gsf_emergency_4 asks if this setup is “not even wait‑free?” and drops a Wikipedia link like a mic. Others crack jokes about the author’s ominous chant: .await .await—the jump scare that makes your code stop and everyone else pile in. Mrkeen swings in with a meme hammer: “This is just dining philosophers,” a classic story of everyone grabbing forks (locks) and going hungry. Some cheer the “single global lock” as practical—one big bouncer, fewer fights. Others clutch pearls, accusing it of turning modern async into old‑school blocking. The vibe: half “keep it simple,” half “this is how deadlocks happen,” with enough await jokes to fill a horror movie.

Key Points

  • Single-threaded cooperative concurrency prevents data races at runtime but does not remove the need for logical mutual exclusion.
  • Placing await within code that must be atomic can introduce logical races, suggesting explicit annotation of atomic segments (e.g., Kotlin-style).
  • TigerBeetle implements implicit exclusion via a single-threaded event loop, serializing mutations to shared Compaction state in callbacks written in Zig.
  • Making exclusion explicit in TigerBeetle would likely require a broad mutex over Compaction, effectively devolving into a single global lock.
  • This tension reflects differing paradigms: CSP-style (independent threads, minimal shared state) versus actor/state machine style (large shared state, event-driven steps).

Hottest takes

"async mutexes... are a strong anti pattern and red flag" — pwnna
"aren't actors share nothing by design?" — didibus
"This is just dining philosophers" — mrkeen
Made with <3 by @siedrix and @shesho from CDMX. Powered by Forge&Hive.