[Haskell-cafe] MVar considered harmful
b at chreekat.net
Wed Dec 19 21:33:51 UTC 2018
Interesting. I have indeed seen enough cases of "Blocked indefinitely on
MVar" to suggest they might be difficult to handle correctly!
On Wed, Dec 19, 2018, 23:02 Станислав Черничкин <schernichkin at gmail.com
> Recently I had an interesting discussion on MVars with cats-effect library
> designers. Cats-effect brings MVar synchronization primitive along with
> other IO stuff to the Scala programming language. I tried to persuade them
> to include some Control.Concurrent.MVar’s functions to the library but has
> failed completely. Moreover, now I think that MVar is a poor choice for
> basic synchronization primitive. Your may find discussion here
> https://github.com/typelevel/cats-effect/issues/451 and event try to
> advocate, tl;dr. Anyway, what is so wrong with MVar?
> 1. It’s complex. Each MVar has 2 state transitions, each may block.
> 2. It does not play well in presence of asynchronous exceptions.
> More specifically, `take` and `put` operations should be balanced (each
> `take` must be followed by `put`) this force programmer to mask
> asynchronous exceptions during the MVar acquisition and since `take`
> function may block, this will delay task cancelation. Well, you may argue
> what the `takeMVar` function is actually interruptible, but I’m going to
> show an easier approach which renders interpretability magic unnecessary.
> What could be the sensible alternative? Guy from the cats-effect suggested
> me IVar + atomic reference (IORef). This pattern separates concern of
> blocking (synchronization) from the atomic mutation. So everything can be
> represented as atomic reference with IVar inside. Just look at this
> beautiful mutex implementation
> (By ”beautiful” I mean approach itself of course, but not the Scala’s
> syntax. Scala is one of most ugliest girls after C++ I was forced to date
> with by my employer for money. Thankfully he didn’t force me to do the same
> things with her grandma Java).
> For people who don’t read Scala, the approach is fairly simple. Each
> thread which want to touch mutex, will create IVar, atomically swap it in
> the IORef masked (note, that IORef’s operations non-blocking), unmask and
> wait for previous become available IVar *unmasked*. Then it will either
> perform it’s operations or fail due to the interruption or exception and
> trigger newly installed IVar anyway. It just works. Without any
> «interruptible» magic.
> So, which benefits can we get?
> 1. Simpler implementation of basic primitives. Obliviously IORef is
> fairly simple. IVar is also mind be simpler than MVar, and possibly faster
> (just “possibly”, I don’t know how it’s implemented, but I guess lesser
> state transitions implies less logic).
> 2. Simplified deadlock analysis. Really, we have only IVar with
> only one state transition and only one potentially blocking operation.
> 3. Magicless support of interruptions. We don’t need to separate
> mask/uninterruptibleMask anymore, because all updates are non-blocking, and
> all waits are unmasked.
> Haskell-Cafe mailing list
> To (un)subscribe, modify options or view archives go to:
> Only members subscribed via the mailman list are allowed to post.
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the Haskell-Cafe