Example 17-4. Example:
g :- forked_computation |
attach ==>
expression :- expression |
Threads can be created by executing an attach. The left side must be of type '$ATTACH' or '$ATTACH{T}'. If the left side is of type '$ATTACH{T}', the return type of the right side must be a subtype of 'T'. If the left side is of type '$ATTACH', the right side must not return a value. There must be no iterators on the right side.
When an attach is executed, the following takes place in strict order:
The left side is evaluated.
$ATTACH and $ATTACH{T} both subtype from $LOCK. If the synchronization object of the left side is locked by another thread, the executing thread is suspended until it becomes unlocked.
Any local variables on the right side are evaluated.
A new thread is created to execute the right side. This new thread is attached to the synchronization object of the left side. The new thread receives a unique copy of every local variable; changes to these locals by the originating thread are not observed by the new thread. Similarly, if 'out' and 'inout' arguments occur on the right side, changes to local variables are not be observed by the originating thread. The rules for memory consistency (See Memory consistency) apply for other variables such as object attributes.
When execution of the right side completes, the new thread terminates, detaches itself, and enqueues the return value or increments the counter, if appropriate.
Attached threads may be thought of as producers that enqueue their return value (or increment a counter) when they terminate.
Every pSather thread is attached to exactly one $ATTACH object; even the main routine is attached to an unnamed object. The thread executing a par statement implicitly creates an $ATTACH object and forks a thread to execute the body. The newly created thread, as well as all threads created by fork statements syntactically in the par body, are attached to this same unnamed object. The thread executing a par statement blocks until there are no threads attached to the object. This ensures that all threads created by a fork have completed before execution continues past the par.