Class AltingBarrier
- java.lang.Object
-
- org.jcsp.lang.Guard
-
- org.jcsp.lang.AltingBarrier
-
public class AltingBarrier extends Guard
This is the front-end for a barrier that can be used as aGuard
in anAlternative
.Description
An alting barrier is represented by a family ofAltingBarrier
front-ends. Each process using the barrier must do so via its own front-end. A new alting barrier is created by the staticcreate
method, which returns an array of front-ends. If new processes need to be enrolled, further front-ends may be made from an existing one (seeexpand
andcontract
). A process may temporarillyresign
from a barrier and, later, re-enroll
.To use this barrier, a process simply includes its given
AltingBarrier
front-end in aGuard
array associated with anAlternative
. Its index will be selected if and only if all parties (processes) to the barrier similarly select it (using their own front-ends).If a process wishes to commit to this barrier (i.e. not offer it as a choice in an
Alternative
), it maysync
on it. However, if all parties only do this, a non-altingBarrier
would be more efficient. A further shortcut (over using anAlternative
) is provided topoll
this barrier for completion.An
AltingBarrier
front-end may only be used by one process at a time (and this is checked at run-time). A process may communicate a non-resigned front-end to another process; but the receiving process mustmark
it before using it and, of course, the sending process must not continue to use it. If a process terminates holding a front-end, it may be recycled for use by another process viareset
.Priorities
These do not -- and cannot -- apply to selection between barriers. ThepriSelect()
method works locally for the process making the offer. If this were allowed, one process might offer barrierx
with higher priority than barriery
... and another process might offer them with its priorities the other way around. In which case, it would be impossible to resolve a choice in favour ofx
ory
in any way that satisfied the conflicting priorities of both processes.However, the
priSelect()
method is allowed for choices including barrier guards. It honours the respective priorities defined between non-barrier guards ... and those between a barrier guard and non-barrier guards (which guarantees, for example, immediate response to a timeout from ever-active barriers). Relative priorities between barrier guards are inoperative.Misuse
The implementation defends against misuse, throwing anAltingBarrierError
error when riled. See the documentation forAltingBarrierError
for circumstances.Example 0 (a single alting barrier)
Here is a simple gadget with two modes of operation, switched by a click event (operated externally by a button in the application below). Initially, it is in individual mode -- represented here by incrementing a number and outputting it (as aString
to change the label on its controlling button) as often as it can. Its other mode is group, in which it can only work if all associated gadgets are also in this mode. Group work consists of a single decrement and output of the number (to its button's label). It performs group work as often as the group will allow (i.e. until it, or one of its partner gadgets, is clicked back to individual mode).import org.jcsp.lang.*; public class AltingBarrierGadget0 implements CSProcess { private final AltingChannelInput click; private final AltingBarrier group; private final ChannelOutput configure; public AltingBarrierGadget0 ( AltingChannelInput click, AltingBarrier group, ChannelOutput configure ) { this.click = click; this.group = group; this.configure = configure; } public void run () { final Alternative clickGroup = new Alternative (new Guard[] {click, group}); final int CLICK = 0, GROUP = 1; int n = 0; configure.write (String.valueOf (n)); while (true) { configure.write (Color.green) // pretty while (!click.pending ()) { // individual work mode n++; // work on our own configure.write (String.valueOf (n)); // work on our own } click.read (); // must consume the click configure.write (Color.red); // pretty boolean group = true; // group work mode while (group) { switch (clickGroup.priSelect ()) { // offer to work with the group case CLICK: click.read (); // must consume the click group = false; // back to individual work mode break; case GROUP: n--; // work with the group configure.write (String.valueOf (n)); // work with the group break; } } } } }
Here is code for a system of buttons and gadgets, synchronised by an alting barrier. Note that this single event needs an array ofAltingBarrier
front-ends to operate -- one for each gadget:import org.jcsp.lang.*; import org.jcsp.plugNplay.*; public class AltingBarrierGadget0Demo0 { public static void main (String[] argv) { final int nUnits = 8; // make the buttons final One2OneChannel[] event = Channel.one2oneArray (nUnits); final One2OneChannel[] configure = Channel.one2oneArray (nUnits); final boolean horizontal = true; final FramedButtonArray buttons = new FramedButtonArray ( "AltingBarrier: Gadget 0, Demo 0", nUnits, 120, nUnits*100, horizontal, configure, event ); // construct an array of front-ends to a single alting barrier final AltingBarrier[] group = AltingBarrier.create (nUnits); // make the gadgets final AltingBarrierGadget0[] gadgets = new AltingBarrierGadget0[nUnits]; for (int i = 0; i < gadgets.length; i++) { gadgets[i] = new AltingBarrierGadget0 (event[i], group[i], configure[i]); } // run everything new Parallel ( new CSProcess[] { buttons, new Parallel (gadgets) } ).run (); } }
The very simple "group" work in the above example consists of actions performed independently by each gadget (decrementing the number on its button's label). The (alting) barrier synchronisation ensures that these decrements keep in step with each other.A more interesting gadget would work with other gadgets for group work that really did require them all to be engaged. For example, they resume operation of a machine that would be dangerous if some gadgets (perhaps those responsible for safety aspects) were doing their individual work.
Example 1 (lots of alting barriers)
This example derives from a pathological challenge to the management of choice between multiway synchronisations raised by Michael Goldsmith (Formal Systems Europe). There are three processes (P
,Q
andR
) and theee events (a
,b
andc
).P
offers eventsa
andb
;Q
offers eventsb
andc
; andR
offers eventsc
anda
. IfP
andQ
synchronise onb
, they do something (possibly together) then start again. Similarly ifQ
andR
synchronise onc
or ifR
andP
synchronise ona
. In CSP, the expression is trivial:P = ((a -> P0); P) [] ((b -> P1); P), and where c is not in the alphabet of P Q = ((b -> Q0); Q) [] ((c -> Q1); Q), and where a is not in the alphabet of Q R = ((c -> R0); R) [] ((a -> R1); R), and where b is not in the alphabet of R SYSTEM = (P || Q || R) \ {a, b, c}
To impact their environment (and avoid divergence), the sub-processesP0
,P1
,Q0
,Q1
,R0
andR1
will engage in external events (i.e. not justa
,b
orc
). Additionally,P1
andQ0
(triggered byb
) may engage in other hidden events, not given in the above. The same forQ1
andR0
(triggered byc
) and forR1
andP0
(triggered bya
).In our version, there are
N
processes and events arranged (logically) around a circle. Each process is either off or on standby, switching between these states on random timeouts. Each process is also attached to a personal button that it uses to indicate its state. When off, it colours its button black; when on standby, light gray.When on standby, each process offers
(span+1)
events: a timeout, the event with it on the circle and the next(span-1)
events going (say) clockwise. It the timeout occurs, it switches to its off state. If one of the events (AltingBarrier
) occurs, it must have occured for a consecutive block ofspan
processes (including this one ... somewhere) around the circle. This group now go into a playing state.Not mentioned before is a rail track, made of channels, running round the circle. When playing, the process furthest uptrack choses a colour and sends this to its partners down the track (to which the mulitway synchronisation ensures this group has exclusive access). Each process in the playing group then flashes its button with that colour a fixed (parametrised) number of times. The rate of flashing is coordinated by the
AltingBarrier
multiway synchronisation event common to the group -- the furthest uptrack process only keeping time for this. After playing, the process switches to its off state.[Note: the above
SYSTEM
hasN
equal to3
,span
equal to2
, no off state and no timeout on standby. The channels used to flash the buttons are the external events mentioned and the rail track channels are the hidden extras.]Here is the code for these processes. As usual, the constructor just saves all parameters:
import org.jcsp.lang.*; import org.jcsp.awt.*; import java.awt.Color; import java.util.Random; public class AltingBarrierGadget1 implements CSProcess { private final AltingBarrier[] barrier; private final AltingChannelInput in, click; private final ChannelOutput out, configure; private final Color offColour, standbyColour; private final int offInterval, standbyInterval; private final int playInterval, flashInterval; public AltingBarrierGadget1 ( AltingBarrier[] barrier, AltingChannelInput in, ChannelOutput out, AltingChannelInput click, ChannelOutput configure, Color offColour, Color standbyColour, int offInterval, int standbyInterval, int playInterval, int flashInterval ) { this.barrier = barrier; this.in = in; this.out = out; this.click = click; this.configure = configure; this.offColour = offColour; this.standbyColour = standbyColour; this.offInterval = offInterval; this.standbyInterval = standbyInterval; this.playInterval = playInterval; this.flashInterval = flashInterval; }
Thebarrier
array gives this gadget access to the multiway events shared with adjacent siblings. Thein
andout
channel ends are part of the rail track this gadget uses later (when playing). Theclick
andconfigure
channels attach this gadget to its button. Theclick
channel is never used by this gadget -- it's included for completeness should anyone wish to enhance its behaviour. The other parameters are just data.The
run()
method controls switching between off, standby and playing states. The latter is the choice between all the multiway syncs (and the timeout). It is handled by a fair select on theAlternative
, constructed just once (before loop entry):public void run () { CSTimer tim = new CSTimer (); final Random random = new Random (); final Guard[] standbyGuard = new Guard[barrier.length + 1]; for (int i = 0; i < barrier.length; i++) { standbyGuard[i] = barrier[i]; } standbyGuard[barrier.length] = tim; final int TIMEOUT = barrier.length; Alternative standbyAlt = new Alternative (standbyGuard); configure.write (Boolean.FALSE); // disable mouse clicks // (not used by this gadget) while (true) { configure.write (offColour); tim.sleep (random.nextInt (offInterval)); configure.write (standbyColour); tim.setAlarm (tim.read () + random.nextInt (standbyInterval)); int choice = standbyAlt.fairSelect (); // magic synchronisation if (choice != TIMEOUT) { play (choice, random, tim); } } }
Here is the playing code. Initially, a colour is chosen and passed down the playing group's section of rail track, to which it has exclusive access. The flashing group is coordinated through the group's common event, with just one of them keeping time.private void play (int choice, Random random, CSTimer tim) { final boolean RIGHTMOST = (choice == 0); final boolean LEFTMOST = (choice == (barrier.length - 1)); Color colour = null; if (RIGHTMOST) { colour = new Color (random.nextInt ()); } else { colour = (Color) in.read (); } Color bright = colour.brighter (); if (!LEFTMOST) out.write (colour); // pass it on final AltingBarrier focus = barrier[choice]; final int count = playInterval/flashInterval; long timeout = tim.read () + flashInterval; boolean bright = true; for (int i = 0; i < count; i++) { configure.write (bright ? brighter : colour); bright = !bright; if (RIGHTMOST) { tim.after (timeout); timeout += flashInterval; } focus.sync (); } } }
Here is code setting up a "circle" of these gadgets, buttons and alting barriers. The buttons are laid out in a row, so that the rightmost button is actually on the "left" of the leftmost button. Care needs to be taken to distribute thespan
front-ends for eachAltingBarrier
to the correct gadgets -- see the re-arrangement below:import org.jcsp.lang.*; import org.jcsp.util.*; import org.jcsp.plugNplay.*; import java.awt.Color; import java.util.Random; public class AltingBarrierGadget1Demo0 { public static void main (String[] argv) { final int nUnits = 30, span = 6; final int offInterval = 800, standbyInterval = 1000; // milliseconds final int playInterval = 10000, flashInterval = 500; // milliseconds final Color offColour = Color.black, standbyColour = Color.lightGray; // make the buttons final One2OneChannel[] click = Channel.one2oneArray (nUnits, new OverWriteOldestBuffer (1)); final One2OneChannel[] configure = Channel.one2oneArray (nUnits); final boolean horizontal = true; final FramedButtonArray buttons = new FramedButtonArray ( "AltingBarrier: Gadget 1, Demo 0", nUnits, 100, nUnits*50, horizontal, configure, click ); // construct nUnits barriers, each with span front-ends ... AltingBarrier[][] ab = new AltingBarrier[nUnits][]; for (int i = 0; i < nUnits; i++) { ab[i] = AltingBarrier.create (span); } // re-arrange front-ends, ready for distribution to processes ... AltingBarrier[][]barrier = new AltingBarrier[nUnits][span]; for (int i = 0; i < nUnits; i++) { for (int j = 0; j < span; j++) { barrier[i][j] = ab[(i + j) % nUnits][j]; } } // make the track and the gadgets One2OneChannel[] track = Channel.one2oneArray (nUnits); AltingBarrierGadget1[] gadgets = new AltingBarrierGadget1[nUnits]; for (int i = 0; i < nUnits; i++) { gadgets[i] = new AltingBarrierGadget1 ( barrier[i], track[(i + 1)%nUnits], track[i], click[i], configure[i], offColour, standbyColour, offInterval, standbyInterval, playInterval, flashInterval ); } // run everything new Parallel ( new CSProcess[] { buttons, new Parallel (gadgets) } ).run (); } }
For fun, here is another application program for the same gadget. It allows a much larger system to be built, laying out the circle of buttons in a grid, row by row. The rightmost button on each row is to the left of the leftmost button on the next row down. The next row down from the bottom row is the top row. The buttons and itsclick
andconfigure
channels are now two dimensional structures. The barriers, gadgets and rail track are still one dimensional. Only code differences from the above are shown:import org.jcsp.lang.*; import org.jcsp.util.*; import org.jcsp.plugNplay.*; import java.awt.Color; import java.util.Random; public class AltingBarrierGadget1Demo1 { public static void main (String[] argv) { final int width = 30, depth = 20; final int nUnits = width*depth; ... the other system parameters (final ints and Colors) final One2OneChannel[][] click = new One2OneChannel[depth][]; for (int i = 0; i < depth; i++) { click[i] = Channel.one2oneArray (width, new OverWriteOldestBuffer (1)); } final One2OneChannel[][] configure = new One2OneChannel[depth][]; for (int i = 0; i < depth; i++) { configure[i] = Channel.one2oneArray (width); } final FramedButtonGrid buttons = new FramedButtonGrid ( "AltingBarrier: Gadget 1, Demo 1", depth, width, 20 + (depth*50), width*50, configure, click ); ... construct nUnits barriers and the track exactly as before AltingBarrierGadget1[] gadgets = new AltingBarrierGadget1[nUnits]; for (int i = 0; i < nUnits; i++) { gadgets[i] = new AltingBarrierGadget1 ( barrier[i], track[(i + 1)%nUnits], track[i], click[i/width][i%width], configure[i/width][i%width], offColour, standbyColour, offInterval, standbyInterval, playInterval, flashInterval ); } ... build and run the buttons and gadgets in parallel } }
Other Examples
Thealting-barriers
directory injcsp-demos
contains other gadgets in a similar vein.
These are similar toAltingBarrierGadget2
AltingBarrierGadget1
, but sit on a 2-way circular railtrack offering to synchronise in the samespan
-groups. Their difference is the game they play when synchronised: pass-the-parcel up and down their section of track, with the parcel's (rapid) progress indicated by writing on the button labels. These gadgets also enable their buttons when playing and finish their game when any one, or more, of their buttons is clicked -- or they get bored and timeout.
Along with their attached buttons, these form a two dimensional structure covering the surface of a torus. The gadgets on the top row are adjacent to the gadgets on the bottom row. The gadgets on the left column are adjacent to the gadgets on the right column. The demonstration program,AltingBarrierGadget3
AltingBarrierGadget3Demo0
, asks the user to choose between various shapes and sizes for the synchronisation groups (pluses, crosses and circles) -- but all groups have the same shape and size.Creation and distribution of the barriers is not done by the demonstration program but, more simply, by the gadgets themselves. Each
AltingBarrierGadget3
belongs to many synchronisation groups, but has lead responsibility for one. It services the input end of a single channel and is given the (shared) output ends of the service channels to the other gadgets in the group it is leading. [Note: the giver of those output ends is the demonstration program.] It creates the alting barrier (and some other things -- see below) for its lead group. Distribution is by I/O-PAR exchange over their service channels as the gadgets initialise. Each gadget sends the things it made to the gadgets in the group it is leading and receives the same from the leaders of its other synchronisation groups. This is the only use they make of these channels.A synchronised group plays a simple counting game until one of its buttons is clicked or the countdown reaches zero. Termination of the game is, and has to be, simultaneous. This is managed by a shared termination flag, safely operated through phased barrier synchronisation (which lets any process in the group set it in an even phase, with all processes acting on it in the odd phases). Shared label and colour variables (for the group's buttons) are operated similarly. The shared variables are distributed (as fields of a shared object) by the leader gadget, along with the group's alting barrier front-ends, during initialisation.
The group's
AltingBarrier
is used to separate the phases. Alting capability on this barrier enables rapid response to any button click on the group to end the game. The lead gadget controls timing: it alts between a countdown timeout, its button click and a cancel message from the rest of the group (should any of their buttons be clicked) -- following any of these with the barrier sync, scheduling the next phase. The other gadgets alt between their button click and the barrier: response to a click being the (timeout) cancel message to the leader then wait for the barrier; response to the barrier being the next phase.The
Any2One
cancel channel is a mulitplexing relay from the non-lead buttons to the leader gadget. It is constructed by the lead gadget and distributed to its team alongside the shared variables. The cancel channel must be overwriting buffered to avoid deadlock -- the same as the click channels from buttons. The cancel channel must be cleared at the start of each game -- same as the click channels.USER GAME: run the demo program on a 30x20 grid (expand to full screen), with circle shapes (say), a radius of 3, off and standBy intervals of 1000 (millisecs), play interval of 10000 (millisecs) and a count interfavl of 200 (millisecs). Your challenge is to zap all the coloured shapes away before any of their counts reach zero and the end of the world happens, :). How long can you survive?!!
These are the same as the previous (AltingBarrierGadget4
AltingBarrierGadget3
) gadgets, except that they do not assume that all the synchronisation groups to which they belong have the same shape or size. While they do know the size of the group they lead (from the length of the channel of output ends they are given), that is all they know. In particular, they do not know how many items (barriers etc.) to expect from the leaders of their other groups in the opening exchange.This is solved by giving each gadget a global barrier on which their parallel outputting processes synchronise when they finish their distribution. After this synchronisation, all exchanges must have finished and they can tell their gadgets to proceed.
The demonstration program for these gadgets just asks for a size for synchronisation groups and allocates (lead) shapes randomly. It could randomise the sizes as well, but the smaller patterns would always emerge dominant in the synchronisations achieved (simply because they require fewer gadgets to be simultaneously on standby -- i.e. offering mode) and the consequent games.
USER GAME: same as before, except with a span (rather than radius) of 3.
These are the same asAltingBarrierGadget5
AltingBarrierGadget4
, except for the technique used to signal the end of the initial exchange of information amongst the synchronisation groups. They use a global alting barrier on which both the outputting and inputting partners in the exchange offer to synchronise -- the former when finished outputting and the latter as an alternative to inputting. This is, perhaps, more elegant than the conventional barrier and channel used by theAltingBarrierGadget4
gadgets and exercises theexpand()
andcontract()
methods.USER GAME: same as before, except with a span (rather than radius) of 3.
The unbuffered service channels used byAltingBarrierGadget6
AltingBarrierGadget3
,AltingBarrierGadget4
andAltingBarrierGadget5
(in the opening I/O-PAR exchange of information amongst each playing group) force the leaders to synchronise with each of their team members. This is no problem forAltingBarrierGadget3
, since all groups have the same size and it receives as many messages as it sends; knowing how many messages it is sending, it knows how large its reception arrays should be. This is not the case forAltingBarrierGadget4
andAltingBarrierGadget5
, which must first receive into collection objects that can expand to any size.AltingBarrierGadget6
performs an asynchronous opening exchange of information, using the collection objects directly to buffer the communication messages and no channels. Further, no internal parallelism is needed for this exchange: the gadgets first add all their messages to the collections held by the rest of their team; then, they synchronise on the global barrier (a non-alting one, the same as used byAltingBarrierGadget4
s); finally, they extract the information sent by the leaders of the other teams to which they belong. As before, the barrier synchronisation is crucial for the correctness of this exchange, ensuring that all messages are in place before they are gathered.USER GAME: same as before, except with a span (rather than radius) of 3.
- Author:
- P.H. Welch
- See Also:
Barrier
,Alternative
-
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description void
contract()
This contracts by one the number of processes enrolled in this alting barrier.void
contract(AltingBarrier[] ab)
This contracts the number of processes enrolled in this alting barrier.static AltingBarrier
create()
This creates a new alting barrier with an (initial) enrollment count of1
.static AltingBarrier[]
create(int n)
This creates a new alting barrier with an (initial) enrollment count ofn
.void
enroll()
A process may enroll only if it is resigned.AltingBarrier
expand()
This expands by one the number of processes enrolled in this alting barrier.AltingBarrier[]
expand(int n)
This expands the number of processes enrolled in this alting barrier.void
mark()
A process may hand its barrier front-end over to another process, but the receiving process must invoke this method before using it.boolean
poll(long offerTime)
This is a simple way to poll for synchonisation on anAltingBarrier
without having to set up anAlternative
.void
reset()
This resets a front-end for reuse.void
resign()
A process may resign only if it is enrolled.void
sync()
This is a simple way to perform a committed synchonisation on anAltingBarrier
without having to set up anAlternative
.
-
-
-
Method Detail
-
create
public static AltingBarrier[] create(int n)
This creates a new alting barrier with an (initial) enrollment count ofn
. It provides an array ofn
front-ends to this barrier. It is the invoker's responsibility to install one of these (by constructor orset
method) in each process that will be synchronising on the barrier, before firing up those processes.Note: each process must use a different front-end to the barrier. Usually, a process retains an
AltingBarrier
front-end throughout its lifetime -- however, seemark
.- Parameters:
n
- the number of processes enrolled (initially) on this barrier.- Returns:
- an array of
n
front-ends to this barrier. - Throws:
IllegalArgumentException
- ifn
<=0
.
-
create
public static AltingBarrier create()
This creates a new alting barrier with an (initial) enrollment count of1
. It provides a single front-end to the barrier, from which others may be generated (seeexpand()
) -- usually one-at-a-time to feed processes individually forked (by aProcessManager
). It is the invoker's responsibility to install each one (by constructor orset
method) in the process that will be synchronising on the barrier, before firing up that process. Usually, a process retains anAltingBarrier
front-end throughout its lifetime -- however, seemark
.Note: if a known number of processes needing the barrier are to be run (e.g. by a
Parallel
), creating the barrier with an array of front-ends usingcreate(n)
would be more convenient.- Returns:
- a single front-end for this barrier.
-
expand
public AltingBarrier[] expand(int n)
This expands the number of processes enrolled in this alting barrier.Use it when an enrolled process is about to go
Parallel
itself and some/all of those sub-processes also need to be enrolled. It returns an array new front-ends for this barrier. It is the invoker's responsibility to pass these on to those sub-processes.Note that if there are
x
sub-processes to be enrolled, this method must be invoked with an argument of(x - 1)
. Pass the returnedAltingBarrier
s to any(x - 1)
of those sub-processes. Pass thisAltingBarrier
to the last one.Before using its given front-end to this barrier, each sub-process must
mark
it to take ownership. [Actually, only the sub-process given the original front-end (which may be running in a different thread) really has to do this.]Following termination of the
Parallel
, the original process must take back ownership of its originalAltingBarrier
(loaned to one of the sub-processes, which may have been running on a different thread) bymark
ing it again.Also following termination of the
Parallel
, the original process must contract the number of processes enrolled on the barrier. To do this, it must have retained the front-end array returned by this method and pass it tocontract
.- Parameters:
n
- the number of processes to be added to this barrier.- Returns:
- an array of new front-ends for this barrier.
- Throws:
IllegalArgumentException
- ifn
<=0
.AltingBarrierError
- if currently resigned or not owner of this front-end.
-
expand
public AltingBarrier expand()
This expands by one the number of processes enrolled in this alting barrier.Use it when an enrolled process is about to fork a new process (using
ProcessManager
) that also needs to be enrolled. It returns an new front-end for this barrier. It is the invoker's responsibility to pass it to the new process.Before terminating, the forked process should
contract
(by one) the number of processes enrolled in this barrier. Otherwise, no further synchronisations on this barrier would be able to complete.- Returns:
- a new front-end for this barrier.
- Throws:
AltingBarrierError
- if currently resigned or not owner of this front-end.
-
contract
public void contract(AltingBarrier[] ab)
This contracts the number of processes enrolled in this alting barrier. The given front-ends are discarded.Use it following termination of a
Parallel
, some/all of whose sub-processes were enrolled by being given front-ends returned byexpand
. See the documentation forexpand
.Warning: only the process that went
Parallel
should invoke this method -- never one of the sub-processes.Warning: never invoke this method whilst processes using its argument's front-ends are running.
Warning: do not attempt to reuse any of the argument elements afterwards -- they front-end nothing.
- Parameters:
ab
- the front-ends being discarded from this barrier. This array must be unaltered from one previously delivered by anexpand
.- Throws:
IllegalArgumentException
- ifab
isnull
or zero length.AltingBarrierError
- if the given array is not one previously delivered by anexpand(n)
, or the invoking process is currently resigned or not the owner of this front-end.
-
contract
public void contract()
This contracts by one the number of processes enrolled in this alting barrier. This front-end cannot not be used subsequently.This method should be used on individually created front-ends (see
expand()
) when, and only when, the process holding it is about to terminate. Normally, that process would have been forked by the process creating this barrier.Warning: do not try to use this front-end following invocation of this method -- it no longer fronts anything.
- Throws:
AltingBarrierError
- if currently resigned or not the owner of this front-end.
-
resign
public void resign()
A process may resign only if it is enrolled. A resigned process may not offer to synchronise on this barrier (until a subsequentenroll
). Other processes can complete the barrier (represented by this front-end) without participation by the resigned process.Unless all processes synchronising on this barrier terminate in the same phase, it is usually appropriate for a terminating process to resign first. Otherwise, its sibling processes will never be able to complete another synchronisation.
Note: a process must not transfer its front-end to another process whilst resigned from the barrier -- see
mark
.- Throws:
AltingBarrierError
- if currently resigned.
-
enroll
public void enroll()
A process may enroll only if it is resigned. A re-enrolled process may resume offering to synchronise on this barrier (until a subsequentresign
). Other processes cannot complete the barrier (represented by this front-end) without participation by the re-enrolled process.Note: timing re-enrollment on a barrier usually needs some care. If the barrier is being used for synchronising phases of execution between a set of processes, it is crucial that re-enrollment occurs in an appropriate (not arbitrary) phase. If the trigger for re-enrollment comes from another enrolled process, that process should be in such an appropriate phase. The resigned process should re-enroll and, then, acknowledge the trigger. The triggering process should wait for that acknowledgement. If the decision to re-enroll is internal (e.g. following a timeout), a buddy process, enrolled on the barrier, should be asked to provide that trigger when in an appropriate phase. The buddy process, perhaps specially built just for this purpose, polls a service channel for that question when in that phase.
- Throws:
AltingBarrierError
- if currently enrolled.
-
mark
public void mark()
A process may hand its barrier front-end over to another process, but the receiving process must invoke this method before using it. Beware that the process that handed it over must no longer use it.Note: a process must not transfer its front-end to another process whilst resigned from the barrier -- see
resign
. The receiving process assumes this is the case. This mark will fail if it is not so.See
expand(n)
for an example pattern of use.- Throws:
AltingBarrierError
- if the front-end is resigned.
-
reset
public void reset()
This resets a front-end for reuse. It still fronts the same barrier. Following this method, this front-end is enrolled on the barrier and not owned by any process.Warning: this should only be used to recycle a front-end whose process has terminated. It should not be used to transfer a front-end between running processes (for which
mark
should be used).Example:
AltingBarrier[] action = AltingBarrier.create (n); Parallel[] system = new Parallel[n]; for (int i = 0; i < system.length; i++) { system[i] = new Something (action[i], ...); } while (true) { // invariant: all 'action' front-ends are enrolled on the barrier. // invariant: all 'action' front-ends are not yet owned by any process. system.run (); // assume: no 'system' process discards (contracts) its 'action' front-end. // note: some 'system' processes may have resigned their 'action' front-ends. // note: in the next run of 'system', its processes may be different // from the point of view of the 'action' front-ends. for (int i = 0; i < action.length; i++) { action[i].reset (); } // deduce: loop invariant re-established. }
-
sync
public void sync()
This is a simple way to perform a committed synchonisation on anAltingBarrier
without having to set up anAlternative
. For example, ifgroup
is anAltingBarrier
, then:group.sync ();
saves first having to construct the single guarded:Alternative groupCommit = new Alternative (new Guard[] {group});
and then:groupCommit.select ();
If this is the only method of synchronisation performed by all parties to this barrier, a non-altingBarrier
would be more efficient.Important note: following a
select
,priSelect
orfairSelect
on anAlternative
that returns the index of anAltingBarrier
, that barrier synchronisation has happened. Do not proceed to invoke thissync
method -- unless, of course, you want to wait for a second synchronisation.
-
poll
public boolean poll(long offerTime)
This is a simple way to poll for synchonisation on anAltingBarrier
without having to set up anAlternative
. The parameter specifies how long this poll should leave its offer to synchronise on the table. Iftrue
is returned, the barrier has completed. Iffalse
, the barrier was unable to complete within the time specified (i.e. at no time were all parties making an offer).For example, if
group
is anAltingBarrier
, then:if (group.poll (offerTime)) { ... group synchronisation achieved } else { ... group synchronisation failed (within offerTime millisecs) }
is equivalent to:groupTimer.setAlarm (groupTimer.read () + offerTime); if (groupPoll.priSelect () == 0) { ... group synchronisation achieved } else { ... group synchronisation failed (within offerTime millisecs) }
where first would have to have been constructed:CSTimer groupTimer = new CSTimer (); Alternative groupPoll = new Alternative (new Guard[] {group, groupTimer});
Note: polling algorithms should generally be a last resort! If all parties to this barrier only use this method, synchronisation depends on all their poll periods coinciding. AnofferTime
of zero is allowed: if all other parties are offering, the barrier will complete -- otherwise, the poll returns immediately. However, if more than one party only ever polls like this, no synchronisation will ever take place.- Parameters:
offerTime
- the time (in milliseconds) that this offer to synchronise should be left on the table.- Returns:
true
if and only if the barrier completes within time specifed.
-
-