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 ABSL_NAMESPACE_BEGIN 28 29 // BlockingCounter 30 // 31 // This class allows a thread to block for a pre-specified number of actions. 32 // `BlockingCounter` maintains a single non-negative abstract integer "count" 33 // with an initial value `initial_count`. A thread can then call `Wait()` on 34 // this blocking counter to block until the specified number of events occur; 35 // worker threads then call 'DecrementCount()` on the counter upon completion of 36 // their work. Once the counter's internal "count" reaches zero, the blocked 37 // thread unblocks. 38 // 39 // A `BlockingCounter` requires the following: 40 // - its `initial_count` is non-negative. 41 // - the number of calls to `DecrementCount()` on it is at most 42 // `initial_count`. 43 // - `Wait()` is called at most once on it. 44 // 45 // Given the above requirements, a `BlockingCounter` provides the following 46 // guarantees: 47 // - Once its internal "count" reaches zero, no legal action on the object 48 // can further change the value of "count". 49 // - When `Wait()` returns, it is legal to destroy the `BlockingCounter`. 50 // - When `Wait()` returns, the number of calls to `DecrementCount()` on 51 // this blocking counter exactly equals `initial_count`. 52 // 53 // Example: 54 // BlockingCounter bcount(N); // there are N items of work 55 // ... Allow worker threads to start. 56 // ... On completing each work item, workers do: 57 // ... bcount.DecrementCount(); // an item of work has been completed 58 // 59 // bcount.Wait(); // wait for all work to be complete 60 // 61 class BlockingCounter { 62 public: BlockingCounter(int initial_count)63 explicit BlockingCounter(int initial_count) 64 : count_(initial_count), num_waiting_(0) {} 65 66 BlockingCounter(const BlockingCounter&) = delete; 67 BlockingCounter& operator=(const BlockingCounter&) = delete; 68 69 // BlockingCounter::DecrementCount() 70 // 71 // Decrements the counter's "count" by one, and return "count == 0". This 72 // function requires that "count != 0" when it is called. 73 // 74 // Memory ordering: For any threads X and Y, any action taken by X 75 // before it calls `DecrementCount()` is visible to thread Y after 76 // Y's call to `DecrementCount()`, provided Y's call returns `true`. 77 bool DecrementCount(); 78 79 // BlockingCounter::Wait() 80 // 81 // Blocks until the counter reaches zero. This function may be called at most 82 // once. On return, `DecrementCount()` will have been called "initial_count" 83 // times and the blocking counter may be destroyed. 84 // 85 // Memory ordering: For any threads X and Y, any action taken by X 86 // before X calls `DecrementCount()` is visible to Y after Y returns 87 // from `Wait()`. 88 void Wait(); 89 90 private: 91 Mutex lock_; 92 int count_ ABSL_GUARDED_BY(lock_); 93 int num_waiting_ ABSL_GUARDED_BY(lock_); 94 }; 95 96 ABSL_NAMESPACE_END 97 } // namespace absl 98 99 #endif // ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_ 100