<INTERFACE> The <CD/Barrier/ structure <SEEALSO> <STRREF TOPID/CML/ </SEEALSO> <PP> The <STRREF TOPID NOLINK/Barrier/ structure provides support for barrier synchronization with global state. Note that unlike most other synchronization mechnisms in CML, barriers do not have event-value operations. </PP> <SPEC> <TYPE><TYPARAM>'a</TYPARAM><ID>barrier</ID></TYPE> <COMMENT> <PP> This is the type constructor for a barrier. </PP> </COMMENT> </SPEC> <SPEC> <TYPE><TYPARAM>'a</TYPARAM><ID>enrollment</ID></TYPE> <COMMENT> <PP> This type constructor represents an enrollment on a barrier. Enrollments are used to synchronize on barriers. </PP> </COMMENT> </SPEC> <SPEC> <VAL>barrier<TY>('a -> 'a) -> 'a -> 'a barrier</TY></VAL> <COMMENT> <PROTOTY> barrier update init </PROTOTY> creates a new barrier with the update function <ARG>update</ARG> and the initial state <ARG>init</ARG>. The state is updated each time the barrier is synchronized on by the enrolled threads. </COMMENT> </SPEC> <SPEC> <VAL>enroll<TY>'a barrier -> 'a enrollment</TY></VAL> <COMMENT> <PROTOTY> enroll bar </PROTOTY> enrolls on the barrier, returning a new <TYREF>enrollment</TYREF>. The (unenforced) convention is that each enrolled thread belongs to a thread and that a thread owns at most one enrollment on a given barrier. </COMMENT> </SPEC> <SPEC> <VAL>wait<TY>'a enrollment -> 'a</TY></VAL> <RAISES><EXNREF>Fail</EXNREF> <COMMENT> <PROTOTY> wait ebar </PROTOTY> waits on the barrier until all of the enrolled threads are waiting, at which point the state is updated and the resulting state value is returned to the waiting threads. If another thread is already waiting on this enrollment or if the enrollment has been resigned, then the exception <EXNREF>Fail</EXNREF> is raised. <PP> Note that if the update function for the barrier raises an exception, then this exception is raised for each waiting thread by <VALREF>wait</VALREF>. </PP> </COMMENT> </SPEC> <SPEC> <VAL>resign<TY>'a enrollment -> unit</TY></VAL> <RAISES><EXNREF>Fail</EXNREF> <COMMENT> <PROTOTY> resign ebar </PROTOTY> resigns from the enrollment <ARG>ebar</ARG>. Resigning from an already resigned enrollment is ignored, but if another thread is waiting on this enrollment, then the exception <EXNREF>Fail</EXNREF> is raised. </COMMENT> </SPEC> <SPEC> <VAL>value<TY>'a enrollment -> 'a</TY></VAL> <RAISES><EXNREF>Fail</EXNREF> <COMMENT> <PROTOTY> value ebar </PROTOTY> gets the current value of the barrier's state. <PP> Note that if the convention of one-thread per enrollment is followed, then this operation is free of races, since the state is stable between barrier synchronizations. </PP> </COMMENT> </SPEC> <PP> Barriers can be used to implement clock and phased synchronization. For example, consider the following code: `let val clock = <VALREF>Barrier.barrier</VALREF> (fn x => x+1) 0 fun spawnChild () = let val bar = <VALREF>Barrier.enroll</VALREF> clock fun loop () = if (<VALREF>Barrier.wait</VALREF> bar = 5) then () else loop() in <VALREF>CML.spawn</VALREF> loop end in <VALREF>Barrier.enroll</VALREF> clock; spawnChild (); spawnChild (); <VALREF>Barrier.resign</VALREF> clock end` In this example, two threads are spawned, which then synchronize on the barrier five times. To avoid a race condition between enrollment and the first synchronization, the parent thread enrolls on the barrier prior to spawning its children and then resigns after the children have been enrolled by the <CD>spawnChild</CD> function. </PP> </INTERFACE>