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