blocking_counter.h 3.7 KB

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