00001 // 00002 // Copyright 2017 The Abseil Authors. 00003 // 00004 // Licensed under the Apache License, Version 2.0 (the "License"); 00005 // you may not use this file except in compliance with the License. 00006 // You may obtain a copy of the License at 00007 // 00008 // https://www.apache.org/licenses/LICENSE-2.0 00009 // 00010 // Unless required by applicable law or agreed to in writing, software 00011 // distributed under the License is distributed on an "AS IS" BASIS, 00012 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 // See the License for the specific language governing permissions and 00014 // limitations under the License. 00015 // 00016 // ----------------------------------------------------------------------------- 00017 // blocking_counter.h 00018 // ----------------------------------------------------------------------------- 00019 00020 #ifndef ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_ 00021 #define ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_ 00022 00023 #include "absl/base/thread_annotations.h" 00024 #include "absl/synchronization/mutex.h" 00025 00026 namespace absl { 00027 00028 // BlockingCounter 00029 // 00030 // This class allows a thread to block for a pre-specified number of actions. 00031 // `BlockingCounter` maintains a single non-negative abstract integer "count" 00032 // with an initial value `initial_count`. A thread can then call `Wait()` on 00033 // this blocking counter to block until the specified number of events occur; 00034 // worker threads then call 'DecrementCount()` on the counter upon completion of 00035 // their work. Once the counter's internal "count" reaches zero, the blocked 00036 // thread unblocks. 00037 // 00038 // A `BlockingCounter` requires the following: 00039 // - its `initial_count` is non-negative. 00040 // - the number of calls to `DecrementCount()` on it is at most 00041 // `initial_count`. 00042 // - `Wait()` is called at most once on it. 00043 // 00044 // Given the above requirements, a `BlockingCounter` provides the following 00045 // guarantees: 00046 // - Once its internal "count" reaches zero, no legal action on the object 00047 // can further change the value of "count". 00048 // - When `Wait()` returns, it is legal to destroy the `BlockingCounter`. 00049 // - When `Wait()` returns, the number of calls to `DecrementCount()` on 00050 // this blocking counter exactly equals `initial_count`. 00051 // 00052 // Example: 00053 // BlockingCounter bcount(N); // there are N items of work 00054 // ... Allow worker threads to start. 00055 // ... On completing each work item, workers do: 00056 // ... bcount.DecrementCount(); // an item of work has been completed 00057 // 00058 // bcount.Wait(); // wait for all work to be complete 00059 // 00060 class BlockingCounter { 00061 public: 00062 explicit BlockingCounter(int initial_count) 00063 : count_(initial_count), num_waiting_(0) {} 00064 00065 BlockingCounter(const BlockingCounter&) = delete; 00066 BlockingCounter& operator=(const BlockingCounter&) = delete; 00067 00068 // BlockingCounter::DecrementCount() 00069 // 00070 // Decrements the counter's "count" by one, and return "count == 0". This 00071 // function requires that "count != 0" when it is called. 00072 // 00073 // Memory ordering: For any threads X and Y, any action taken by X 00074 // before it calls `DecrementCount()` is visible to thread Y after 00075 // Y's call to `DecrementCount()`, provided Y's call returns `true`. 00076 bool DecrementCount(); 00077 00078 // BlockingCounter::Wait() 00079 // 00080 // Blocks until the counter reaches zero. This function may be called at most 00081 // once. On return, `DecrementCount()` will have been called "initial_count" 00082 // times and the blocking counter may be destroyed. 00083 // 00084 // Memory ordering: For any threads X and Y, any action taken by X 00085 // before X calls `DecrementCount()` is visible to Y after Y returns 00086 // from `Wait()`. 00087 void Wait(); 00088 00089 private: 00090 Mutex lock_; 00091 int count_ GUARDED_BY(lock_); 00092 int num_waiting_ GUARDED_BY(lock_); 00093 }; 00094 00095 } // namespace absl 00096 00097 #endif // ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_