Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:27:28

0001 //
0002 // Copyright 2017 The Abseil Authors.
0003 //
0004 // Licensed under the Apache License, Version 2.0 (the "License");
0005 // you may not use this file except in compliance with the License.
0006 // You may obtain a copy of the License at
0007 //
0008 //      https://www.apache.org/licenses/LICENSE-2.0
0009 //
0010 // Unless required by applicable law or agreed to in writing, software
0011 // distributed under the License is distributed on an "AS IS" BASIS,
0012 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013 // See the License for the specific language governing permissions and
0014 // limitations under the License.
0015 //
0016 // -----------------------------------------------------------------------------
0017 // blocking_counter.h
0018 // -----------------------------------------------------------------------------
0019 
0020 #ifndef ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_
0021 #define ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_
0022 
0023 #include <atomic>
0024 
0025 #include "absl/base/thread_annotations.h"
0026 #include "absl/synchronization/mutex.h"
0027 
0028 namespace absl {
0029 ABSL_NAMESPACE_BEGIN
0030 
0031 // BlockingCounter
0032 //
0033 // This class allows a thread to block for a pre-specified number of actions.
0034 // `BlockingCounter` maintains a single non-negative abstract integer "count"
0035 // with an initial value `initial_count`. A thread can then call `Wait()` on
0036 // this blocking counter to block until the specified number of events occur;
0037 // worker threads then call 'DecrementCount()` on the counter upon completion of
0038 // their work. Once the counter's internal "count" reaches zero, the blocked
0039 // thread unblocks.
0040 //
0041 // A `BlockingCounter` requires the following:
0042 //     - its `initial_count` is non-negative.
0043 //     - the number of calls to `DecrementCount()` on it is at most
0044 //       `initial_count`.
0045 //     - `Wait()` is called at most once on it.
0046 //
0047 // Given the above requirements, a `BlockingCounter` provides the following
0048 // guarantees:
0049 //     - Once its internal "count" reaches zero, no legal action on the object
0050 //       can further change the value of "count".
0051 //     - When `Wait()` returns, it is legal to destroy the `BlockingCounter`.
0052 //     - When `Wait()` returns, the number of calls to `DecrementCount()` on
0053 //       this blocking counter exactly equals `initial_count`.
0054 //
0055 // Example:
0056 //     BlockingCounter bcount(N);         // there are N items of work
0057 //     ... Allow worker threads to start.
0058 //     ... On completing each work item, workers do:
0059 //     ... bcount.DecrementCount();      // an item of work has been completed
0060 //
0061 //     bcount.Wait();                    // wait for all work to be complete
0062 //
0063 class BlockingCounter {
0064  public:
0065   explicit BlockingCounter(int initial_count);
0066 
0067   BlockingCounter(const BlockingCounter&) = delete;
0068   BlockingCounter& operator=(const BlockingCounter&) = delete;
0069 
0070   // BlockingCounter::DecrementCount()
0071   //
0072   // Decrements the counter's "count" by one, and return "count == 0". This
0073   // function requires that "count != 0" when it is called.
0074   //
0075   // Memory ordering: For any threads X and Y, any action taken by X
0076   // before it calls `DecrementCount()` is visible to thread Y after
0077   // Y's call to `DecrementCount()`, provided Y's call returns `true`.
0078   bool DecrementCount();
0079 
0080   // BlockingCounter::Wait()
0081   //
0082   // Blocks until the counter reaches zero. This function may be called at most
0083   // once. On return, `DecrementCount()` will have been called "initial_count"
0084   // times and the blocking counter may be destroyed.
0085   //
0086   // Memory ordering: For any threads X and Y, any action taken by X
0087   // before X calls `DecrementCount()` is visible to Y after Y returns
0088   // from `Wait()`.
0089   void Wait();
0090 
0091  private:
0092   Mutex lock_;
0093   std::atomic<int> count_;
0094   int num_waiting_ ABSL_GUARDED_BY(lock_);
0095   bool done_ ABSL_GUARDED_BY(lock_);
0096 };
0097 
0098 ABSL_NAMESPACE_END
0099 }  // namespace absl
0100 
0101 #endif  // ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_