Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame^] | 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_ ABSL_GUARDED_BY(lock_); |
| 92 | int num_waiting_ ABSL_GUARDED_BY(lock_); |
| 93 | }; |
| 94 | |
| 95 | } // namespace absl |
| 96 | |
| 97 | #endif // ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_ |