Question about 'Tackling the Awkward Squad'

Steinitz, Dominic J
29 Jan 2001 09:56:00 Z

This is probably superfluous now but I still don't understand Hugs' behaviour. I ran the following with ghc 4.08.1:

module Main(main) where

import Concurrent

main =
   do chan <- newChan
      writeChan chan "One"
      dup <- dupChan chan
      writeChan chan "Two"
      x <- readChan dup
      y <- readChan chan
      z <- readChan chan
      putStrLn (x++y++z)

I expected the answer "TwoOneTwo" but instead got

$ ./main
d:\dom\hugs98\concurrent\main.exe: no threads to run:  infinite loop or

which confirmed the problem that Don highlighted.

With Hugs I got the following:

Main> main

(232 reductions, 458 cells)

which was puzzling. I'm running  Version: May 1999 with -98.

Dominic. on 28/01/2001 11:18:00
To:	don_wakefield
bcc:	Dominic Steinitz
Subject:	RE: Question about 'Tackling the Awkward Squad'


Crumbs!  You're right!

The MVars that are drawn as heavy black boxes in Figure 7 of Tackling
the Awkward Squad are used to block the consumer when it catches up
with the producer.  But if there is more than one consumer, it's not
OK to leave these MVars empty.  Instead, getChan should do a put after
its take; or, more elegantly, should use readMVar, which has the
semantics of take-followed-by-put:

    getchan (read, write)
      = do { head_var <- takeMVar read ;
             MkItem val new_head <- readMVar head_var ;
             putMVar read new_head ;
             return val }

Concurrent programming is tricky.  I owe you a beer!

I'll fix the version on the Web


| when I ran across what appears to be an error. On page 34, while
| discussing Channels, he proposes a function called dupChan:
|    dupChan (read, write)
|      = do { new_read <- newEmptyMVar ;
|             hole <- takeMVar write ;
|             putMVar write hole ;
|             putMVar new_read hole ;
|             return (new_read, write) }
| The rationale is given thusly:
|  "For example, consider a multi-cast channel, in which there are
|   multiple readers, each of which should see all the values written to
|   the channel ... The idea is that the channel returned by dupChan can
|   be read independently of the original, and sees all (and only) the
|   data written to the channel after the dupChan call."
| But earlier he has defined getChan thusly:
|    getchan (read, write)
|      = do { head_var <- takeMVar read ;
|             MkItem val new_head <- takeMVar head_var ;
|             putMVar read new_head ;
|             return val }
| Since the line which performs the 'takeMVar head_var' leaves the MVar
| referenced by head_var empty, the dupChan 'new_read' Stream
| should block
| when the reader tries to *also* use getChan on this Stream, isn't this
| so? Am I missing some subtlety? I drew all the pictures :^)~
| --
| Don Wakefield                              Mentor Graphics Corporation
| (503) 685-1262                             8005 S.W. Boeckman Road
|                  Wilsonville, OR 97070-7777
| _______________________________________________
| Haskell mailing list

Haskell mailing list

21st century air travel