Barriers are objects that are used to synchronize multiple threads. A barrier has a
count
that determines how many "arrivals" (calls to
barrier-wait) have to occur before these calls return.
The main usage of barriers is to ensure that a group of threads have all finished some stage of an algorithm before any of them proceeds.
The typical way of using a barrier is to make one with a count that is the same as the number of threads that are going to work in parallel and then create the threads to do the work. When each thread has done its work, it synchronizes with the others by calling barrier-wait. In most cases barrier-wait is the only barrier API that is used.
For example, assume you have a task that be broken into two stages, where each stage can be done in parallel by several threads, but the first stage must be completely finished before any processing of the second stage can start.
Then the code will do:
(let ((barrier (mp:make-barrier num-of-processes)))
(dotimes (p num-of-processes)
(mp:process-run-function (format nil "Task worker ~d" p)
()
#'(lambda (process-number barrier)
(do-first-stage process-number)
(mp:barrier-wait barrier)
(do-second-stage process-number))
p
barrier)))
It is also possible to use the barrier to block an indefinite number (up to
most-positive-fixnum
) of processes, until another process decides that they can go. For this the barrier is made with
count
t (or
most-positive-fixnum
). The other process then uses
barrier-disable to "open" the barrier. If required, the barrier can be enabled again by
barrier-enable.
See also barrier-block-and-wait.
LispWorks User Guide and Reference Manual - 21 Dec 2011