latch.hpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // Distributed under the Boost Software License, Version 1.0. (See
  2. // accompanying file LICENSE_1_0.txt or copy at
  3. // http://www.boost.org/LICENSE_1_0.txt)
  4. // (C) Copyright 2013 Vicente J. Botet Escriba
  5. #ifndef BOOST_THREAD_LATCH_HPP
  6. #define BOOST_THREAD_LATCH_HPP
  7. #include <boost/thread/detail/config.hpp>
  8. #include <boost/thread/detail/delete.hpp>
  9. #include <boost/thread/detail/counter.hpp>
  10. #include <boost/thread/mutex.hpp>
  11. #include <boost/thread/lock_types.hpp>
  12. #include <boost/thread/condition_variable.hpp>
  13. #include <boost/chrono/duration.hpp>
  14. #include <boost/chrono/time_point.hpp>
  15. #include <boost/assert.hpp>
  16. #include <boost/config/abi_prefix.hpp>
  17. namespace boost
  18. {
  19. class latch
  20. {
  21. /// @Requires: count_ must be greater than 0
  22. /// Effect: Decrement the count. Unlocks the lock and notify anyone waiting if we reached zero.
  23. /// Returns: true if count_ reached the value 0.
  24. /// @ThreadSafe ensured by the @c lk parameter
  25. bool count_down(unique_lock<mutex> &lk)
  26. /// pre_condition (count_ > 0)
  27. {
  28. BOOST_ASSERT(count_ > 0);
  29. if (--count_ == 0)
  30. {
  31. ++generation_;
  32. lk.unlock();
  33. cond_.notify_all();
  34. return true;
  35. }
  36. return false;
  37. }
  38. /// Effect: Decrement the count is > 0. Unlocks the lock notify anyone waiting if we reached zero.
  39. /// Returns: true if count_ is 0.
  40. /// @ThreadSafe ensured by the @c lk parameter
  41. bool try_count_down(unique_lock<mutex> &lk)
  42. {
  43. if (count_ > 0)
  44. {
  45. return count_down(lk);
  46. }
  47. return true;
  48. }
  49. public:
  50. BOOST_THREAD_NO_COPYABLE( latch)
  51. /// Constructs a latch with a given count.
  52. latch(std::size_t count) :
  53. count_(count), generation_(0)
  54. {
  55. }
  56. /// Destructor
  57. /// Precondition: No threads are waiting or invoking count_down on @c *this.
  58. ~latch()
  59. {
  60. }
  61. /// Blocks until the latch has counted down to zero.
  62. void wait()
  63. {
  64. boost::unique_lock<boost::mutex> lk(mutex_);
  65. std::size_t generation(generation_);
  66. cond_.wait(lk, detail::not_equal(generation, generation_));
  67. }
  68. /// @return true if the internal counter is already 0, false otherwise
  69. bool try_wait()
  70. {
  71. boost::unique_lock<boost::mutex> lk(mutex_);
  72. return (count_ == 0);
  73. }
  74. /// try to wait for a specified amount of time is elapsed.
  75. /// @return whether there is a timeout or not.
  76. template <class Rep, class Period>
  77. cv_status wait_for(const chrono::duration<Rep, Period>& rel_time)
  78. {
  79. boost::unique_lock<boost::mutex> lk(mutex_);
  80. std::size_t generation(generation_);
  81. return cond_.wait_for(lk, rel_time, detail::not_equal(generation, generation_))
  82. ? cv_status::no_timeout
  83. : cv_status::timeout;
  84. }
  85. /// try to wait until the specified time_point is reached
  86. /// @return whether there were a timeout or not.
  87. template <class Clock, class Duration>
  88. cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time)
  89. {
  90. boost::unique_lock<boost::mutex> lk(mutex_);
  91. std::size_t generation(generation_);
  92. return cond_.wait_until(lk, abs_time, detail::not_equal(generation, generation_))
  93. ? cv_status::no_timeout
  94. : cv_status::timeout;
  95. }
  96. /// Decrement the count and notify anyone waiting if we reach zero.
  97. /// @Requires count must be greater than 0
  98. void count_down()
  99. {
  100. boost::unique_lock<boost::mutex> lk(mutex_);
  101. count_down(lk);
  102. }
  103. /// Effect: Decrement the count if it is > 0 and notify anyone waiting if we reached zero.
  104. /// Returns: true if count_ was 0 or reached 0.
  105. bool try_count_down()
  106. {
  107. boost::unique_lock<boost::mutex> lk(mutex_);
  108. return try_count_down(lk);
  109. }
  110. void signal()
  111. {
  112. count_down();
  113. }
  114. /// Decrement the count and notify anyone waiting if we reach zero.
  115. /// Blocks until the latch has counted down to zero.
  116. /// @Requires count must be greater than 0
  117. void count_down_and_wait()
  118. {
  119. boost::unique_lock<boost::mutex> lk(mutex_);
  120. std::size_t generation(generation_);
  121. if (count_down(lk))
  122. {
  123. return;
  124. }
  125. cond_.wait(lk, detail::not_equal(generation, generation_));
  126. }
  127. void sync()
  128. {
  129. count_down_and_wait();
  130. }
  131. /// Reset the counter
  132. /// #Requires This method may only be invoked when there are no other threads currently inside the count_down_and_wait() method.
  133. void reset(std::size_t count)
  134. {
  135. boost::lock_guard<boost::mutex> lk(mutex_);
  136. //BOOST_ASSERT(count_ == 0);
  137. count_ = count;
  138. }
  139. private:
  140. mutex mutex_;
  141. condition_variable cond_;
  142. std::size_t count_;
  143. std::size_t generation_;
  144. };
  145. } // namespace boost
  146. #include <boost/config/abi_suffix.hpp>
  147. #endif