One of a series of tutorials about Scheme in general
and the Wraith Scheme interpreter in particular.
Copyright © 2011
Jay Reynolds Freeman,
all rights reserved.
Personal Web Site: http://JayReynoldsFreeman.com
This brief tutorial describes how to use Wraith Scheme's enhancements whereby one of a group of parallel Wraith Scheme processes can send messages to another. In previous tutorials, I have already indicated that such processes can share information by way of variable bindings in the top-level environment -- one process may set a variable for another to examine at will. Now let's talk about a different form of communication.
The term "message" is widely used in computer science, and depending on what background you have, you may already have some expectation of what it means, and of how messages between processes are transmitted. In Wraith Scheme, the meaning is as follows: One Wraith Scheme process sends a message to another by getting the destination process to evaluate a Scheme expression in its own top-level environment. This is indeed a different kind of communication than using variable bindings: The idea is that the one Wraith Scheme process makes something happen in another.
Wraith Scheme has a single procedure for sending such messages, and several other procedures to keep track of what the message-sending mechanism is doing. These procedures are all enhancements. The main procedure is "e::tell-kitten". It takes two arguments, the first being a kitten number and the second being the message to be evaluated by the destination. For example, if some Wraith Scheme process would like to tell kitten number six to add two and two, it can evaluate
(e::tell-kitten 6 '(+ 2 2)) ;; ==> #t, and kitten six gets the message "(+ 2 2)".
Note the quote in the second argument. It is there because in a procedure application of "e::tell-kitten" -- as in all procedure applications -- the arguments are evaluated before being passed to the procedure code itself. The argument "'(+ 2 2)" (with the quote) evaluates to "(+ 2 2)" (no quote), and that last is what is passed to "e::tell-kitten" and thence on to kitten number six. Thus it is kitten number six that performs the addition. Without the quote, as in
(e::tell-kitten 6 (+ 2 2)) ;; ==> #t, and kitten six gets the message "4".
the argument "(+ 2 2)" gets evaluated by the kitten that is sending the message, to "4", and it is "4" that is passed as the message to kitten six. In this case, kitten six does no addition, it merely prints out the result of the addition that was performed by the sending kitten.
Therefore, when you use "e::tell-kitten", you will usually be quoting the second argument. Sometimes you won't; for example, perhaps the kitten sending the message has to go through some complicated process to decide what message to send, in which case the procedure application of "e::tell-kitten" might look like this.
(e::tell-kitten 6 (figure-out-what-message-to-send-and-return-it)) ;; ==> #t ...
In this case, the procedure application mechanism has evaluated "(figure-out-what-message-to-send-and-return-it)", which presumably returns the necessary message, which will be passed to kitten 6.
So we know how to send messages, and we know that the receiving kitten will evaluate them in its top-level environment when it gets them, but when will the receiving kitten get its messages? Procedure "e::tell-kitten" will run promptly, but if the destination kitten is busy at the time -- if it is running some Scheme code -- it will not get any messages until it has finished. Wraith Scheme interprocess messages are delivered only when the destination process is idle.
Pending messages for a kitten are placed in a queue. The word is used in the everyday sense of a line such as you might see at a ticket office or a bank teller's window. People join the line at the back as they arrive, and whoever is first in line is the next customer to be assisted. So it is with computer queues -- messages to any given kitten are handled in first-come, first-served order, one at a time, when the kitten is not otherwise busy.
There is no magic about these queues, incidentally -- they are just lists in Scheme main memory, one for each kitten. The message-handling mechanism knows where they are. Ordinary Scheme operations are used to attach messages at one end of the list and remove them from the other, so it acts like a queue. There is a locking mechanism, as discussed in the tutorial "Parallel Processing", to keep the queue from getting messed up if two messages for one kitten happen to arrive at the same time.
Messages in these queues have priority over expressions typed in at the keyboard. To be sure, if a Wraith Scheme process is already processing something when a message arrives in its queue, it will finish what it is doing, but the moment it returns to top-level, it will start processing messages from the queue, and will continue till the queue is empty. Note in particular, that if you drag or paste a selection of text that contains several Scheme expressions into the Wraith Scheme Input Panel, and messages start showing up in that Wraith Scheme process's queue before all of the pasted expressions have been evaluated, Wraith Scheme will stop processing the expressions from the input panel at first opportunity, and will take messages from the queue instead.
Wraith Scheme provides, as enhancements, several procedures for investigating and modifying these queues.
Procedure "c::kitten-input-queue" returns the kitten's input queue, as a list. There is no guarantee that the queue will be the same for any perceptible amount of time; other processes may be adding to it and the kitten itself may be acting on the messages received.
Procedure "c::kitten-empty-queue?" is a predicate telling whether or not the indicated queue is empty at the moment the procedure is called. Once again, that state may change at any time.
Procedure "c::purge-kitten-queue" empties the queue for the kitten in question. Other processes may of course start filling it up again immediately.
Wraith Scheme also has, as an enhancement, an interrupt mechanism whereby any other process may interrupt a Wraith Scheme process, and cause a Scheme expression to be loaded into its queue, for evaluation. The interrupt mechanism is intended to allow processes other than Wraith Scheme to interrupt Wraith Scheme, perhaps in connection with the Wraith Scheme Foreign Function Interface. See the sections of the Wraith Scheme Help File titled "Foreign Function Interface", and "Details and Procedures for the Interrupt System", for further information.
-- Jay Reynolds Freeman (Jay_Reynolds_Freeman@mac.com)