On 25 May 2010 11:00, Daniel Fischer <daniel.is.fischer@web.de> wrote:
Sorry for the ugly layout:
else do if e then yield else do xs <- readChan ch atomically $ do x <- readTVar n writeTVar n (x + sum xs) loop ch p n
The point is, if the channel is empty, but the producer has not yet finished, don't try to read from the channel (that wouldn't work then), but give the producer the chance to produce the next chunk. Since thread-switching happens on allocation, don't just jump to the next iteration of the loop, but tell the thread manager "I have nothing to do at the moment, you can let somebody else run for a while".
I have encountered cases where yield didn't work reliably (no idea whether that was my fault or the compiler's, but "threadDelay 0" instead of yield worked reliably).
This is where I was getting it all horribly wrong. I assumed that while the loop thread blocked, the other thread would happily carry on producing work. Is there anything I can read to get a better understanding of how the haskell runtime manages these switches? Or is it the OS that takes care of this..?
Here is my new function, with the a call to yield inserted :) loop :: Chan [Integer] -> MVar () -> TVar Integer -> IO Integer loop ch p n = do f <- isEmptyMVar p e <- isEmptyChan ch if not f then atomically (readTVar n) else if e then yield >> loop ch p n else do xs <- readChan ch atomically $ do x <- readTVar n writeTVar n (x + sum xs) loop ch p n Thanks for your help! Ben