blocking_counter.h 4.0 KB

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