blocking_counter.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  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 "absl/base/thread_annotations.h"
  22. #include "absl/synchronization/mutex.h"
  23. namespace absl {
  24. ABSL_NAMESPACE_BEGIN
  25. // BlockingCounter
  26. //
  27. // This class allows a thread to block for a pre-specified number of actions.
  28. // `BlockingCounter` maintains a single non-negative abstract integer "count"
  29. // with an initial value `initial_count`. A thread can then call `Wait()` on
  30. // this blocking counter to block until the specified number of events occur;
  31. // worker threads then call 'DecrementCount()` on the counter upon completion of
  32. // their work. Once the counter's internal "count" reaches zero, the blocked
  33. // thread unblocks.
  34. //
  35. // A `BlockingCounter` requires the following:
  36. // - its `initial_count` is non-negative.
  37. // - the number of calls to `DecrementCount()` on it is at most
  38. // `initial_count`.
  39. // - `Wait()` is called at most once on it.
  40. //
  41. // Given the above requirements, a `BlockingCounter` provides the following
  42. // guarantees:
  43. // - Once its internal "count" reaches zero, no legal action on the object
  44. // can further change the value of "count".
  45. // - When `Wait()` returns, it is legal to destroy the `BlockingCounter`.
  46. // - When `Wait()` returns, the number of calls to `DecrementCount()` on
  47. // this blocking counter exactly equals `initial_count`.
  48. //
  49. // Example:
  50. // BlockingCounter bcount(N); // there are N items of work
  51. // ... Allow worker threads to start.
  52. // ... On completing each work item, workers do:
  53. // ... bcount.DecrementCount(); // an item of work has been completed
  54. //
  55. // bcount.Wait(); // wait for all work to be complete
  56. //
  57. class BlockingCounter {
  58. public:
  59. explicit BlockingCounter(int initial_count)
  60. : count_(initial_count), num_waiting_(0) {}
  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. int count_ ABSL_GUARDED_BY(lock_);
  85. int num_waiting_ ABSL_GUARDED_BY(lock_);
  86. };
  87. ABSL_NAMESPACE_END
  88. } // namespace absl
  89. #endif // ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_