> What is the functional difference between 'rpc' and 'pr' and why the
> specific constraint on 'rpc' being suitable only for stdout?
There is indeed not much difference. 'rpc' is just a special case of
> : (hear (pipe (do 3 (wait 2000) (rpc 'println ''Ok))))
To achieve the same effect with 'pr'
> : (hear (pipe (do 3 (wait 2000) (pr '(println 'Ok)) (flush))))
you have, for one thing, to pass a list. This is sometimes a little
inconvenient, as you end up 'list'ing and 'cons'ing when the list is not
(pr (list 'println *MyVariable))
(rpc 'println *MyVariable)
And, for the second, you need to explicitly specify standard output to
get it work correctly
(hear (pipe (do 3 (wait 2000) (out NIL (pr '(println 'Ok))))))
Your above example worked only because the current output channel in the
'pipe' child process was still on standard output.
Not needing (out NIL ...) is theoretically faster, because the overhead
of setting up the output channel is avoided. Same with the unnecessary
building of the list. That's why it is called "rapid" procedure call in
the reference ;-)
But in total you are right. Practically there is not much difference.
> I see, where can I find this automatic channel, is it a named pipe?
> If not, what channel is used for communication?
It is a normal (unnamed) pipe, which is set up automatically by 'fork'.
The parent takes care to send all data it receives via 'tell' from its
children to all other children to their 'hear'ing pipe. So this is the
easiest, and perhaps also most efficient, way.
> Using 'tell' I cannot send a message to the parent process though. I
Yes, this is correct.
> would like to have the philosophers talking to a monitor process which
> cannot be the parent but must be another child for 'tell' to work. Is
> that correct? How are children supposed to communicate with the
> parent process?
Then you could use 'pipe' instead of 'fork'. The children created by
'pipe' have the same IPC mechanisms set up as by 'fork'.
Another possibility (and probably what I would do) is to create the
monitor process as a separate child. This frees the parent from possibly
time-consuming tasks, and lets it concentrate on the IPC dispatching.
This allows also to have several different monitoring children etc., and
does no harm to the system's stability if the monitor process crashes.
The same philosophy we have when the parent is the DB and GUI server.
> 'tell' seems to be asynchronous. If I want to query the philosopher
Yes, that's right. It will not return anything.
> (de philState ()
> (list *Pid *State *LeftFork *RightFork) )
> .. and in *Monitor process call...
> (let S (tell 'pid P 'philState)
> (println S)
> because 'tell' does not return the result of calling 'philState'. Is
> there a standard/easy way of achieving this?
If the monitor is another child, it could be
(de philState ()
(tell 'pid *Monitor ...) )
If you stay with the monitor being the parent, you could use 'boss':
(boss 'foo 'args ...)
with the same syntax as 'tell' to send something to the boss.
I have that (load "lib/boss.l") in most production applications, and can
later connect to the running application via "bin/psh <port>", and
modify the parent process with e.g. (boss 'load "app/foo.l") without
having to stop and start it.