barrier.qbk 3.27 KB
[/
  (C) Copyright 2007-8 Anthony Williams.
  (C) Copyright 2013 Oliver Kowalke.
  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE_1_0.txt or copy at
  http://www.boost.org/LICENSE_1_0.txt).
]

[section:barriers Barriers]

A barrier is a concept also known as a __rendezvous__, it is a synchronization
point between multiple contexts of execution (fibers). The barrier is
configured for a particular number of fibers (`n`), and as fibers reach the
barrier they must wait until all `n` fibers have arrived. Once the `n`-th
fiber has reached the barrier, all the waiting fibers can proceed, and the
barrier is reset.

The fact that the barrier automatically resets is significant. Consider a case
in which you launch some number of fibers and want to wait only until the
first of them has completed. You might be tempted to use a `barrier(2)` as the
synchronization mechanism, making each new fiber call its [member_link
barrier..wait] method, then calling `wait()` in the launching fiber to wait
until the first other fiber completes.

That will in fact unblock the launching fiber. The unfortunate part is that it
will continue blocking the ['remaining] fibers.

Consider the following scenario:

# Fiber ["main] launches fibers A, B, C and D, then calls `barrier::wait()`.
# Fiber C finishes first and likewise calls `barrier::wait()`.
# Fiber ["main] is unblocked, as desired.
# Fiber B calls `barrier::wait()`. Fiber B is ['blocked!]
# Fiber A calls `barrier::wait()`. Fibers A and B are unblocked.
# Fiber D calls `barrier::wait()`. Fiber D is blocked indefinitely.

(See also [link wait_first_simple_section when_any, simple completion].)

[note It is unwise to tie the lifespan of a barrier to any one of its
participating fibers. Although conceptually all waiting fibers awaken
["simultaneously,] because of the nature of fibers, in practice they will
awaken one by one in indeterminate order.[footnote The current implementation
wakes fibers in FIFO order: the first to call `wait()` wakes first, and so
forth. But it is perilous to rely on the order in which the various fibers
will reach the `wait()` call.] The rest of the waiting fibers will
still be blocked in `wait()`, which must, before returning, access data
members in the barrier object.]

[class_heading barrier]

        #include <boost/fiber/barrier.hpp>

        namespace boost {
        namespace fibers {

        class barrier {
        public:
            explicit barrier( std::size_t);

            barrier( barrier const&) = delete;
            barrier & operator=( barrier const&) = delete;

            bool wait();
        };

        }}


Instances of __barrier__ are not copyable or movable.

[heading Constructor]

        explicit barrier( std::size_t initial);

[variablelist
[[Effects:] [Construct a barrier for `initial` fibers.]]
[[Throws:] [`fiber_error`]]
[[Error Conditions:] [
[*invalid_argument]: if `initial` is zero.]]
]

[member_heading barrier..wait]

        bool wait();

[variablelist
[[Effects:] [Block until `initial` fibers have called `wait` on `*this`. When
the `initial`-th fiber calls `wait`, all waiting fibers are unblocked, and
the barrier is reset. ]]
[[Returns:] [`true` for exactly one fiber from each batch of waiting fibers,
`false` otherwise.]]
[[Throws:] [__fiber_error__]]
]

[endsect]