Chapter 7
Processes
Every program so far has been one process. Ether programs can be many processes at once, each with its own values, instructions and macros, which share nothing and talk only by sending each other messages.
A process is a table
Chapter 1 described a process as values, instructions and macros. It is
literally a table holding those, plus one more stack, the handler
stack, which trust uses. process pushes the table of
the running process:
process keys sort
values: ( ( "h" "i" "m" "v" ) )
The keys are v (values), i (instructions),
m (macros) and h (handler).
Queues
Processes talk through queues. queue makes one and
pushes a pair of its two ends: an output, which you send into, and an
input, which you receive from. unpair takes the pair
apart. send takes a message and an output; receive
takes an input and pushes the next message, waiting until one arrives.
queue unpair = out = in " hello " out send in receive debug
hello values: ( )
A message is copied as it is sent. A thawed object that goes into a queue comes out as a separate object, so the sender and the receiver never share anything that can change:
queue unpair = out = in stack " x " swap push = mine mine out send in receive = theirs " y " mine push del mine size debug theirs size debug
2 1 values: ( )
poll asks whether a message is waiting, without waiting.
Fork
fork takes a list of lists. Every list but the last runs in a
new copy of this process, and the last one runs here. Each copy then
carries on with the rest of the program, so the words after the
fork run once in every process:
{ { " in the copy " debug } { " here " debug } } fork
" after the fork " debug
here after the fork in the copy after the fork values: ( ) values: ( )
The output ends with one values: line per process. A copy
starts with everything this process had, including any queue it made
earlier, so a queue made before the fork connects the copies:
queue unpair = out = in
{ { # 6 # 7 * out send } { in receive debug } } fork
42 values: ( ) values: ( )
Each process takes its turn to run, and a process waiting in
receive lets the others go first. If a process waits for a
message that can never come, because nothing that could send to that queue is
still running, the wait ends with an exception instead of hanging.
Exercise 7.1
Fork a copy that adds up the numbers from 1 to 10 and sends the total to the original process, which prints it.
A correct answer prints:
55 values: ( ) values: ( )
One answer
queue unpair = out = in
{ { # 0 [ # 1 # 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 ] { + } foreach out send }
{ in receive debug } } fork
55 values: ( ) values: ( )
Exercise 7.2
Fork two copies. One sends 20 and the other sends 22; the original receives both messages and prints their sum.
A correct answer prints:
42 values: ( ) values: ( ) values: ( )
One answer
queue unpair = out = in
{ { # 20 out send } { # 22 out send } { in receive in receive + debug } } fork
42 values: ( ) values: ( ) values: ( )
Exercise 7.3
Send a stack holding a through a queue, then push
b onto the original stack. Print the size of the stack that was
received, and then the size of the original.
A correct answer prints:
1 2 values: ( )
One answer
queue unpair = out = in stack \ a swap push = s s out send \ b s push del in receive size debug s size debug
1 2 values: ( )