Hi Tomas,

independent of the discussed problems with 'hear', I would actually not
use 'hear' for this purpose.

If you look in the reference for 'hear', it says "hear is usually only
called explicitly by a top level parent process". The reason is that
upon a 'fork', the 'hear' channel is automatically set up in the child
process to be used by the built-in IPC routines.

As a consequence, if you re-open that channel with 'hear', the child is
effectively cut off from its parent and could, for example, not
synchronize on DB operations.

So the recommended and natural way is to use 'tell'. In combination with
'pid', it can also send messages selectively to other processes.

This solution has the additional advantage that no external fifos are
required.

As an example, I modified your "phil.l" (I hope I understood it). Each
philosopher (process) keeps the PIDs of his neighbors in the global
variables '*LeftNeighbor' and '*RightNeighbor', and the state of the
forks in '*LeftFork' and '*RightFork'. In the beginning, he waits until
he received the PIDs from the parent process.

Cheers,
- Alex
# ~/picolisp/p phil.l
# http://en.wikipedia.org/wiki/Dining_philosophers_problem
# Chandy / Misra solution

# *Philosophers      List of PIDs (process IDs)
# *LeftNeighbor      PID of left neighbor
# *RightNeighbor     PID of right neighbor
# *LeftFork          Left fork (NIL, dirty or clean)
# *RightFork         Right fork (NIL, dirty or clean)

(de log @
   (pass println *Pid *LeftFork *RightFork)
   (flush) )

(de idle ()
   (wait (rand 1000 3000)) )

(de obtain (P)
   (log 'obtain P)
   (cond
      ((= P *LeftNeighbor)
         (if *LeftFork
            (quit "Already have the left fork")
            (setq *LeftFork 'clean) ) )
      ((= P *RightNeighbor)
         (if *RightFork
            (quit "Already have the right fork")
            (setq *RightFork 'clean) ) ) ) )

(de give (P)
   (log 'give P)
   (cond
      ((= P *LeftNeighbor)
         (when (== 'dirty *LeftFork)
            (tell 'pid P 'obtain *Pid)
            (off *LeftFork) ) )
      ((= P *RightNeighbor)
         (when (== 'dirty *RightFork)
            (tell 'pid P 'obtain *Pid)
            (off *RightFork) ) ) ) )

(de grab ()
   (until (and *LeftFork *RightFork)
      (cond
         ((== 'dirty *LeftFork)
            (setq *LeftFork 'clean) )
         ((not *LeftFork)
            (tell 'pid *LeftNeighbor 'give *Pid) ) )
      (cond
         ((== 'dirty *RightFork)
            (setq *RightFork 'clean) )
         ((not *RightFork)
            (tell 'pid *RightNeighbor 'give *Pid) ) )
      (wait 500) ) )

(de phil ()
   (wait NIL (and *LeftNeighbor *RightNeighbor))
   (setq *LeftFork 'dirty)
   (loop
      (log 'thinking)
      (idle)  # think
      (log 'hungry)
      (grab)
      (log 'eating)
      (idle)  # eat
      (setq *LeftFork (setq *RightFork 'dirty)) ) )

(de main (N)
   (setq *Philosophers  # Build a list of PIDs
      (make
         (do N
            (if (fork) (link @) (phil)) ) ) )
   (push '*Bye '(mapc kill *Philosophers))
   (do N  # Send to each philosopher the PIDs of his neighbors
      (tell 'pid (car *Philosophers)
         'setq
         '*LeftNeighbor (last *Philosophers)
         '*RightNeighbor (cadr *Philosophers) )
      (rot *Philosophers) ) )

(main 5)

Reply via email to