Blame view

3rdparty/boost_1_81_0/libs/fiber/doc/barrier.qbk 3.27 KB
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]