
Hi folks I'm having a play with Concurrent Haskell, and came across this in the library. readMVar :: MVar a -> IO a This is a combination of takeMVar and putMVar; ie. it takes the value from the MVar, puts it back, and also returns it. I was just wondering if I understand things correctly. Suppose myMVar is nonempty and I have one thread executing do x <- takeMVar myMVar -- (A) putMVar myMVar x -- (B) return x and another executing putMVar myMVar y -- (C) Questions (1) Is it possible that an evil scheduler will execute (A) then (C) and block on (B)? (2) Is it the case that if myMVar is nonempty and readMVar is chosen for execution, that readMVar myMVar takes the value from myMVar, guaranteed that the _same_ value will be put back immediately, and also returned? (3) If yes to both, what combination of takeMVar and putMVar manages to maintain the lock in between the two? I'm only asking, because I'm trying to cook up some kind of partial evaluator for programs which are being simultaneously edited by fiercely argumentative devils. Kind of `demonic laziness', where the computations decide when _they_ feel like running (eg sometime after the program turns up), rather than the `angelic laziness' we're used to. I'd like to use MVars in a write-once-read-many style, so that once someone fills in a bit of program, it stays put. I'd hate for another devil to sneak in a replacement program just in the twinkling of an eye between taking something out to read and putting it back to be read again. I guess I could use some kind of extra semaphore MVar to ensure that the reader has the lock on the program MVar, but that's more like hard work. Is readMVar what I want? Another more general question would be `is this an utterly stupid thing to do in practice?'. I mean, just consider an evaluator for some simple language (eg arithmetic expressions), implemented by forking a thread for every subcomputation, and using MVars to transmit the values. Is that diabolically slow compared to a normal evaluator? I guess I'll try it, but I was wondering if anyone had any useful experience to share? Cheers Conor

Conor T McBride wrote:
... [questions about operation ordering with MVars]
I'm only asking, because I'm trying to cook up some kind of partial evaluator for programs which are being simultaneously edited by fiercely argumentative devils. Kind of `demonic laziness', where the computations decide when _they_ feel like running (eg sometime after the program turns up), rather than the `angelic laziness' we're used to. I'd like to use MVars in a write-once-read-many style, so that once someone fills in a bit of program, it stays put. I'd hate for another devil to sneak in a replacement program just in the twinkling of an eye between taking something out to read and putting it back to be read again.
If you're really using MVars in write-once read-many style, the semantics of readMVar shouldn't be a problem: * Before the initializing write, all calls to readMVar block. * The initializing take fills the MVar and unblocks all the blocked readers. * Subsequent calls to readMVar should be able to complete gracefully, though calls to readMVar will block temporarily if another call to readMVar gets de-scheduled between the take and the put. If you're not doing this, what are you *actually* trying to do? With multiple writers, of course things get more complicated, but you should be able to organize your code into take...put pairs or calls to withMVar as Andy Moran suggested.
I guess I could use some kind of extra semaphore MVar to ensure that the reader has the lock on the program MVar, but that's more like hard work. Is readMVar what I want?
Another route is to define an algebraic type for the contents of your MVar. If you want to update several fields, atomically, you can write something like (untested): withMVar var (\record -> record{field1 = value1, field2 = value2}) This is a standard trick from the lock-free algorithms community---if you want to change more fields than you can update with a compare-and-swap, allocate a new record and change the pointer instead.
Another more general question would be `is this an utterly stupid thing to do in practice?'. I mean, just consider an evaluator for some simple language (eg arithmetic expressions), implemented by forking a thread for every subcomputation, and using MVars to transmit the values. Is that diabolically slow compared to a normal evaluator?
The MVars implementation won't be particularly efficient---I'd expect it to be diabolically slow, in fact. But it's a perfectly legitamate thing to do in general. It forms the basis for three different functional languages I've worked on: Id (which predates Haskell---MVars were first developed for Id), pH (Id with Haskell syntax, roughly speaking---Arvind and Rishiyur Nikhil have a textbook on pH), and Eager Haskell.
I guess I'll try it, but I was wondering if anyone had any useful experience to share?
It's fun to tinker with this stuff, but you quickly learn that it's going to run slowly unless you're fairly smart. In this respect it's not that much different from laziness. -Jan-Willem Maessen Eager Haskell and pH implementor Id hacker
Cheers
Conor _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
participants (2)
-
Conor T McBride
-
Jan-Willem Maessen - Sun Labs East