1 | // |
2 | // Copyright 2017 The Abseil Authors. |
3 | // |
4 | // Licensed under the Apache License, Version 2.0 (the "License"); |
5 | // you may not use this file except in compliance with the License. |
6 | // You may obtain a copy of the License at |
7 | // |
8 | // https://www.apache.org/licenses/LICENSE-2.0 |
9 | // |
10 | // Unless required by applicable law or agreed to in writing, software |
11 | // distributed under the License is distributed on an "AS IS" BASIS, |
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | // See the License for the specific language governing permissions and |
14 | // limitations under the License. |
15 | // |
16 | // ----------------------------------------------------------------------------- |
17 | // blocking_counter.h |
18 | // ----------------------------------------------------------------------------- |
19 | |
20 | #ifndef ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_ |
21 | #define ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_ |
22 | |
23 | #include "absl/base/thread_annotations.h" |
24 | #include "absl/synchronization/mutex.h" |
25 | |
26 | namespace absl { |
27 | |
28 | // BlockingCounter |
29 | // |
30 | // This class allows a thread to block for a pre-specified number of actions. |
31 | // `BlockingCounter` maintains a single non-negative abstract integer "count" |
32 | // with an initial value `initial_count`. A thread can then call `Wait()` on |
33 | // this blocking counter to block until the specified number of events occur; |
34 | // worker threads then call 'DecrementCount()` on the counter upon completion of |
35 | // their work. Once the counter's internal "count" reaches zero, the blocked |
36 | // thread unblocks. |
37 | // |
38 | // A `BlockingCounter` requires the following: |
39 | // - its `initial_count` is non-negative. |
40 | // - the number of calls to `DecrementCount()` on it is at most |
41 | // `initial_count`. |
42 | // - `Wait()` is called at most once on it. |
43 | // |
44 | // Given the above requirements, a `BlockingCounter` provides the following |
45 | // guarantees: |
46 | // - Once its internal "count" reaches zero, no legal action on the object |
47 | // can further change the value of "count". |
48 | // - When `Wait()` returns, it is legal to destroy the `BlockingCounter`. |
49 | // - When `Wait()` returns, the number of calls to `DecrementCount()` on |
50 | // this blocking counter exactly equals `initial_count`. |
51 | // |
52 | // Example: |
53 | // BlockingCounter bcount(N); // there are N items of work |
54 | // ... Allow worker threads to start. |
55 | // ... On completing each work item, workers do: |
56 | // ... bcount.DecrementCount(); // an item of work has been completed |
57 | // |
58 | // bcount.Wait(); // wait for all work to be complete |
59 | // |
60 | class BlockingCounter { |
61 | public: |
62 | explicit BlockingCounter(int initial_count) |
63 | : count_(initial_count), num_waiting_(0) {} |
64 | |
65 | BlockingCounter(const BlockingCounter&) = delete; |
66 | BlockingCounter& operator=(const BlockingCounter&) = delete; |
67 | |
68 | // BlockingCounter::DecrementCount() |
69 | // |
70 | // Decrements the counter's "count" by one, and return "count == 0". This |
71 | // function requires that "count != 0" when it is called. |
72 | // |
73 | // Memory ordering: For any threads X and Y, any action taken by X |
74 | // before it calls `DecrementCount()` is visible to thread Y after |
75 | // Y's call to `DecrementCount()`, provided Y's call returns `true`. |
76 | bool DecrementCount(); |
77 | |
78 | // BlockingCounter::Wait() |
79 | // |
80 | // Blocks until the counter reaches zero. This function may be called at most |
81 | // once. On return, `DecrementCount()` will have been called "initial_count" |
82 | // times and the blocking counter may be destroyed. |
83 | // |
84 | // Memory ordering: For any threads X and Y, any action taken by X |
85 | // before X calls `DecrementCount()` is visible to Y after Y returns |
86 | // from `Wait()`. |
87 | void Wait(); |
88 | |
89 | private: |
90 | Mutex lock_; |
91 | int count_ GUARDED_BY(lock_); |
92 | int num_waiting_ GUARDED_BY(lock_); |
93 | }; |
94 | |
95 | } // namespace absl |
96 | |
97 | #endif // ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_ |
98 | |