You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

blocking_counter.h 4.1 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  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. {
  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. {
  61. public:
  62. explicit BlockingCounter(int initial_count);
  63. BlockingCounter(const BlockingCounter&) = delete;
  64. BlockingCounter& operator=(const BlockingCounter&) = delete;
  65. // BlockingCounter::DecrementCount()
  66. //
  67. // Decrements the counter's "count" by one, and return "count == 0". This
  68. // function requires that "count != 0" when it is called.
  69. //
  70. // Memory ordering: For any threads X and Y, any action taken by X
  71. // before it calls `DecrementCount()` is visible to thread Y after
  72. // Y's call to `DecrementCount()`, provided Y's call returns `true`.
  73. bool DecrementCount();
  74. // BlockingCounter::Wait()
  75. //
  76. // Blocks until the counter reaches zero. This function may be called at most
  77. // once. On return, `DecrementCount()` will have been called "initial_count"
  78. // times and the blocking counter may be destroyed.
  79. //
  80. // Memory ordering: For any threads X and Y, any action taken by X
  81. // before X calls `DecrementCount()` is visible to Y after Y returns
  82. // from `Wait()`.
  83. void Wait();
  84. private:
  85. Mutex lock_;
  86. std::atomic<int> count_;
  87. int num_waiting_ ABSL_GUARDED_BY(lock_);
  88. bool done_ ABSL_GUARDED_BY(lock_);
  89. };
  90. ABSL_NAMESPACE_END
  91. } // namespace absl
  92. #endif // ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_