
A few thoughts: * IIRC, MVars (in Haskell anyway) also have some fairness guarantees, which I don't see otherwise mentioned in the discussion so far. Compare to STM, where large transactions are susceptible to starvation. * If the goal is to have a simpler base primitive on which to build, everything has to boil down to compare-and-swap, load-linked/store-conditional, etc -- whatever the machine provides. When you start talking about even mutexes and semaphores, you're already dealing with higher-level abstractions, so the thinking about what's the right "primitive" seems silly to me at that point; you should be thinking about what the high-level (user) code should be able to do, and then figure out how to meet in the middle. * If what you're after is *composable* concurrency, simpler locks won't get you that. STM is the best general solution I've seen for this, and if you're doing concurrency stuff in Haskell, I would say use STM unless you have a specific reason to do something else. * Re: async exceptions, you're in the same situation with MVars as you are with all resource-acquiring IO actions in Haskell. `withMVar` and friends cover async-exception safety, and you can't get rid of mask and friends by swapping out MVars with another primitive anyway, because you still need them for acquiring other (non-concurrency related) resources, like files. -Ian