2. MARCO CONCEPTUAL
2.3 PERSPECTIVAS CURRICULARES
2.3.2 Propuesta curricular alternativa
Being able to interrogate message queues, identify messages, and select the order in which to consume them provides the basis for a user-oriented scheduling mechanism.
For example, if an instance services messages from a variety of producers, then it can select its work according to some in-built priority scheme, written by the user. Although the system automatically buffers messages, the user could simulate this if he wished. The classic reader/writer problem could be written so that the 'common buffer' is
— 38 —
actually managed by a separate instance; this taking requests from a "reader" and a "writer" instance. The buffer manager then serves the writer before the reader simply by:
if message writer then ... else
This is simple for the trivial case of a single writer and reader instance pair. If, however, there were many readers and writers then the buffer manager would have to discover which of its messages came from instances executing a write-oriented definition, and which were from a read- oriented definition. This can be done using the ils operator
mentioned above, or by using the write-oriented definition value, to find out whether there are any messages from any writer instances, whoever they may be, before serving read- oriented instances. This is extremely concise!
So far all communication has been with either instances which know of each other personally, or with instances of known definitions. If interacting directly they must have been placed in contact with each other either by being directly related, via default communications paths, or by having been sent their mutual identities via the message system, so that they could communicate directly.
Any instance can send a message to any other instance, so long as it has been given its identity. However, that instance might not know of, and so will not be expecting messages from, such an instance, and because it does not know its identity it cannot specifically ask for its message
- 39 -
to be read in ! If the definition that such an instance is executing is known in advance then, as in the case of the extended reader/writer problem, the message could be retrieved by asking for the message from an instance of that definition. If however the receiver does not know of the sender directly, and does not know which definition it is executing, then it simply knows that it has a message from somewhere, but has no way of directly asking for it. The generality of the message scheme being outlined permits even this sort of situation to be managed sensibly.
Apart from polling the queue to see if there are any messages, either at all or from specific sources or classes
of sender, it is possible for an instance to request the identities of all senders of messages currently in its queue. The system primitive census achieves this. It returns a set (sets are one of the data types in the language) of identities.
This set value can then be examined to decide how to manage the messages in the queue at that time. Unlike the above cases, where only previously known instances could be served, the receiver is now given the identities of all of the senders, from which it can find out what they are doing, and so ask for their messages in whatever order is deemed appropriate.
The mechanism is completely general purpose: if census is given an argument, corresponding to a currently active instance in the system, then it samples the input queue
- 40 -
attached to that instance, otherwise it examines that of the current instance.
A two-way link can establish itself automatically, as once one instance knows another, the second can find out the identity of the sender of the 'anonymous’ message. This is quite an attractive capability, and it permits a system of interacting instances to 'grow' new communications paths as and when desired.
As a data type a set is merely an unordered collection of values. The set returned by census is a set which is composed entirely of instance identities. There are various operations on a set, one is a simple membership predicate:
if census has x then ... else ...
where 'x ' is again a previously known instance value, would test for messages from the above mentioned instance. This is as before. The advantages are only realised when the set of identities is used in conjunction with the is operator discussed earlier, or the classof operator. The operator reports whether a particular instance is executing a particular definition. The classof operator takes an instance and returns its definition value. This definition value may not have been known to that particular instance before. By testing elements of the census set the senders, even if previously unheard of and so with unknown requirements, can always be identified in terms of 'what they are doing' as well as 'who they are'. This permits scheduling-by-activity, as well as scheduling-by-identity.
41
For example, if we take a census of the queue and save it, by:
let census -> ids
then by using an iterative set element selector (which applies a statement to each member of a set, in some 'randomised' order) v/e can service all of those messages from instances performing a certain function, whatever their identities :
forall sender in ids do if sender is tape.driver do
In this way it is possible to test the senders against known definitions, if it was necessary to find out,the definition being executed by any given instance then the classof operator will report this. It is possible, therefore, to write a definition which records the names and activities of all instances which send it messages, even if they were unheard of before the message arrived. It is even possible to write a definition which, depending upon some test, is required to invoke a new instance of its creator:
if ... do new classof input -> x
and so replicate some arm of the system hierarchy.
Note that such high level scheduling is based on the nature of the concurrent entities and their activities, rather than on some 'ad hoc' priority scheme. This mechanism enables the user to write his scheduling algorithms directly into general purpose message managing systems.
- 42 -
These facilities, taken together, support many data handling and communications requirements, and permit instances to schedule their activity in accordance with dynamically variable workloads.
Having outlined how concurrent processes can interact with each other, both asynchronously and nondeterministically, we will move on to explain how they can widen their horizons by examining their environment, inspecting one another directly,