977ed18d
Hu Chunming
提交三方库
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
[/
(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]
|