Unix allows processes to communicate between unidirectional pipes; In close analogy, Muq allows jobs to communicate between unidirectional message streams.
In both cases, a principal motivation is to provide a clean and simple prepackaged solution to the producer-consumer synchronization problem, in which one job produces output which is then consumed by another job: the consumer job needs to stop and wait when no more input is available, and it is usually a good idea for the producer job to stop and wait when the consumer falls behind, rather than filling the database with perhaps megabytes of unconsumed output.
Pipes and message streams both serve as bounded buffers written to by one or more producers and read by one or more consumers; A producer which attempts to write to a full buffer will automatically block until free space becomes available; a consumer which attempts to read from an empty buffer will automaticaly block until input becomes available.
The principal difference between unix pipes and Muq message streams is that pipes are fundamentally structured to pass a flow of bytes, while message streams are fundamentally structured to pass a flow of stackblocks containing arbitrary Muq values, including characters, floats, objects, and even jobs, sessions and message streams, if desired.
There is a limit on the maximum size stackblock which a
given message stream can hold, available as
stream$s.maxPacket
. This is currently a fixed
constant (4095); It may be made variable on a
per-stream basis in a future release.
There is also a limit on the maximum number of stackblocks resident in a given message stream at a given instant; This is currently fixed at 31.
The conventional way to pass text through message streams (that is, to use them as unix-style text streams) is to pass blocks of characters, one line per block. (2) Functions are available to simplify doing unix-style character- or line-oriented I/O through message streams. See section message stream functions.
The standard input and output (and error) of a job will always be message streams.
A pair of vanilla unidirectional message streams may be
combined to produce a bidirectional message stream
simply by pointing their stream$s.twin
properties to each other:
See section makeBidirectionalMessageStream. This works
because all server primitives which read from a stream,
actually read from stream$s.twin
. By default
this is the stream itself, and has no effect, but in a
bidirectional stream it results in the desired
behavior.
Internally, message streams contain job queues on which to place blocked produce and consumer jobs; this functionality is not normally of concern to the Muq programmer, or even directly visible.
Class MessageStream adds the following properties to those of Class Index:
$S.allowReads: T, job or user to allow non-owners to read from stream. $S.allowWrites: T, job or user to allow non-owners to write to stream. $S.column: Number of chars read from current packet so far. $S.byte: Number of bytes of tokens read from stream so far. $S.line: Number of packets or lines read from stream so far. $S.dead: NIL to allow normal I/O; non-NIL to stop it. $S.maxPacket: Maximum size packet which may be written. $S.twin: Self, or twin if stream is bidirectional. $S.inputString: Reserved for supporting compilation from strings. $S.inputStringCursor: Reserved for supporting compilation from strings. $S.inputSubstitute: Reserved for supporting compilation from strings.
Note: For convenience, the $S properties are also available in the public (default) propdir.
The allowReads
and allowWrites
properties allow
the owner of a stream to expand the default read or write
permissions for it. Setting them to t
results in
unrestricted read or write access; Setting them to a job
or user adds access only for that job, or jobs with
@$s.actingUser
set to the given user. This
simplifies implementation of communication mechanisms
between users.
Go to the first, previous, next, last section, table of contents.