Multithreading

When multithreading is enabled (it can be switched on and off in the preferences dialog or the Edit menu), 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 diagrams with multiple threads

Specifying a multithreaded diagram is only slightly harder than specifying a diagram with a single thread.

Spawning threads

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.

Statically spawned threads

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.

Dynamically spawned threads

As a rule, a message sent by an actor to an object (dynamically) spawns a new thread.

So do messages sent to "active objects". An object can be declared to be active by setting the v flag. Example:

worker:BackgroundWorker[v]

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.

Broadcast messages

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.

Specifying the thread where an activity occurs

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.

Instant return

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.

Stopping threads

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.

Returning control flow

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).