Multithreading support is an advanced feature that is available
since version 2.2. If you are not interested, you can completely
ignore it.
If you are interested, you may enable it in the
"Threads" menu.
When multithreading is enabled, you can create diagrams that model
arbitarily many sequences running in parallel, not just a single
one. The sequences can (at your option) be distinguished by the
colours of their corresponding lifelines. There is still no real
parallelism, as the messages must be specified in some order. This
order can be interpreted as one of many possible
interleavings
of the threads. A single-processor system would execute them in a
similar way.
Specifying a multithreaded diagram is only slightly harder than
specifying a diagram with a single thread.
A newly spawned thread can be distinguished from older threads
by the colour of its corresponding lifelines. If you spawn too
many threads, colours may be repeated. Threads have successive
numbers, starting with 0.
Objects that have been declared with the "t" flag
set, for example:
o:Object[t]
have their own (statically spawned) thread. The first thing
that happens on this thread must be a message sent by the
corresponding object.
If there is no object with a "t" flag, there is a
single thread nonetheless. It starts executing when the first
message is sent by an object.
As a rule, a message sent by an actor to an object
(dynamically) spawns a new thread.
Messages sent and received by ordinary objects may also spawn
new threads. In order to specify that such a message is
spawning, use a colon followed by a ">" to
separate the caller from the message. Example:
object:>bar.foo()
This means that
object
spawns a new thread and the first thing this new thread does
is executing the
foo
method of the
bar
object.
Note that you cannot specify answers to messages that spawn
threads. If an object running on a new thread wants to
communicate with the spawning object, it must explicitly send
a message.
A message can have more than one callee, specified in set
notation. In this case, it is a broadcast message. Example:
caller:{callee1,callee2,callee3}.broadcast
A callee may not occur more than once in the callee set, the
caller may not occur at all in there. The effect of a
broadcast message is that a new thread is spawned for each
callee.
It is currently not possible to define mnemonics for objects
that are activated by a broadcast message.
When more than one thread is used, we need to be able to tell on
which of the threads a message occurs. So the level of a caller
(specified in square brackets) may be followed by the number of
the thread, where level and thread are separated by a comma.
Example:
object[0,3]:bar.foo()
This means that
object
is sending a
foo()
message to
bar
on the thread number 3.
If an object is used by a single thread only, the number of the
thread can be omitted. If there is more than one thread using an
object and the thread number is omitted, the editor assumes that
the message is to be sent on the same thread as the most recent
message. If you spawn a new thread, the next message will, if
not otherwise specified, be sent on that new thread. It is also
possible to omit the level and only specify the thread, so
object[,3]:bar.foo()
is equivalent to the example above, as 0 is the default level.
You can also use a mnemonic between square brackets. When a
mnemonic is defined for an object, the mnemonic determines both
the level and the thread number.
Thread numbers can be made visible at your option (see the
"Threads" menu): They are shown at the top of the
active lifelines.
Normally, the focus of a thread's activity stays on the object
that has received the most recent message, unless the thread is
stopped or another message is sent. Sometimes, however, it may
seem inappropriate to have a thread's focus resting on an object
for so long. In that case a message should be ended by an
"&". This means that the answer to the message
will be sent immediately. Note that a message sent later cannot
have the callee of the instantly returning message as a caller
of course. Example:
foo:bar.notify()&
If a spawning message is suffixed with an "&", the
spawned thread does nothing and dies instantly. Such messages
might be interpreted as asynchronous signals.
Normally, a thread runs until the end of the diagram. But maybe
you would like to model that it dies at some point. This is done
by inserting a pseudo message of the form:
object:stop
(where of course also a thread number may be specified).
Stopping a thread may be necessary before an object can be
destroyed, if the thread's activity does not return from the
object otherwise. The text of the pseudo message (i. e.
"stop") will not appear on the diagram. The visible
effect rather is that the corresponding lifeline ends at that
point.
Before an object sends a message, a thread's control flow has to
return to it, which implies that some answers pending on the
thread might have to be sent. Sometimes one wants to manipulate
the control flow like this without the need to send a new
message, e. g. for representing that a certain set of actions is
finished now or for simply doing some "clean-up". This
can be done by inserting a pseudo message consisting of just an
underscore:
object:_
The effect is that enough pending answers will be sent such that
"object"
could
send a message now on its current thread (again, a special
thread number may be specified). The pseudo message does not
appear on the diagram and there will be no extra space consumed
(apart from the space needed for the answers).