A way to form a 'select' on MVars without polling

961 views Asked by At

I have two MVars (well an MVar and a Chan). I need to pull things out of the Chan and process them until the other MVar is not empty any more. My ideal solution would be something like the UNIX select function where I pass in a list of (presumably empty) MVars and the thread blocks until one of them is full, then it returns the full MVar. Try as I might I can think of no way of doing this beyond repeatedly polling each MVar with isEmptyMVar until I get false. This seems inefficient.

A different thought was to use throwTo, but it interrupts what ever is happening in the thread and I need to complete processing a job out the the Chan in an atomic fashion.

A final thought as I'm typing is to create a new forkIO for each MVar which tries to read its MVar then fill a newly created MVar with its own instance. The original thread can then block on that MVar. Are Haskell threads cheap enough to go running that many?

2

There are 2 answers

0
hammar On BEST ANSWER

Haskell threads are very cheap, so you could solve it that way, but it sounds like STM would be a better fit for your problem. With STM you can do

do var <- atomically (takeTMVar a `orElse` takeTMVar b)
   ... do stuff with var

Because of the behavior of retry and orElse, this code tries to get a, then if that fails, get b. If both fail, it blocks until either of them is updated and tries again.

You could even use this to make your own rudimentary version of select:

select :: [TMVar a] -> STM a
select = foldr1 orElse . map takeTMVar
0
Don Stewart On

How about using STM versions, TChan and TVar, with the retry and orElse behavior?

Implementing select is one of STM's nice capabilities. From "Composable Memory Transactions":

Beyond this, we also provide orElse, which allows them to be composed as alternatives, so that the second is run if the first retries (Section 3.4). This ability allows threads to wait for many things at once, like the Unix select system call – except that orElse composes well, whereas select does not.