Above, we described a function which allowed a thread to wait for the completion of another thread. This was useful when there were two related threads, but was not adequate for the situation in which a single thread awaits completion of several other threads. Also, it does not allow several threads to synchronize with each other at a known rendevouz spot. For example, conider the case where we have k (where k > 1) threads performing some iterative calculation based on a matrix. Each thread is responsible for updating its own sub matrix of the larger data structure used as input to each step of the iterative process. In such a case, each thread must stop at the end of each iteration and wait for the other threads to finish that iteration also. Otherwise, one thread would start the next iteration with an inconsistent input matrix made up of partially updated entries.

A Barrier is a synchronization mechanism which solves these two problems. The following functions give the programmer access to the utility of barrier objects. Each barrier acts on a set of threads. The barrier is available to each of these threads and it keeps track of which threads have called reached the barrier point. Each thread signals the barrier that it has reached the rendevouz point by calling wait() with the barrier as an argument.

Barrier(..., Start, on.complete=NULL)
This function constructs a new Barrier object. The arguments passed to ... should be either thread objects or a ThreadGroup. Any thread objects (passed directly or within a group) should of course contain valid thread objects. In principle, each of the threads should not have been started but merely assigned a set of expressions to evaluate when start() is called for this thread. Otherwise The argument Start is a vector of logicals. It is cycled to have length equal to length(list(...)). If the ith element of Start is T, the function start is called with the ith element of list(...) as the argument. In this way, we can start any of the threads when they have been added to the barrier. This avoids any race conditions created by starting a thread that reaches its rendezvous point before being added to the barrier. If this happened, the barrier would never be satisfied as it would wait for this thread that might never wait() on this barrier again. Even if it did, in this case, the barrier would erroneously acknowledge it as completed and the threads would be unsynchronized. Thus the correct approach to creating threads that share a barrier is to create them all with the Thread() function and argument Start = F. Then create the barrier with Start = T. A function can passed via the argument on.complete which will be evaluated the first time that the barrier condition is satisfied (i.e. all threads within the threads variable have reached the rendesvouz point). The function is passed a single argument which is the barrier that has just been statisfied. This function can be used to clear the completed flags so that the barrier can be used again. To reinstate the function so that it is evaluated the next time the condition is met, the function should contain the expression
 setOnComplete(barrier, getOnComplete(barrier))
where barrier is the argument to the function on.complete.
addThread(barrier, ..., start=T)
This allows the programmer to add a thread to the list of threads employed in the barrier. Any number of threads may be passed to the barrier through the ... argument. The start argument behaves in the same manner as in Barrier
wait(barrier)
This function allows a thread to wait until all other threads in the barrier group have reached the relevant barrier point.
Last modified: Tue Feb 11 17:33:30 1997