latch.hpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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> &)
  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. if (count_ == 0) return;
  66. std::size_t generation(generation_);
  67. cond_.wait(lk, detail::not_equal(generation, generation_));
  68. }
  69. /// @return true if the internal counter is already 0, false otherwise
  70. bool try_wait()
  71. {
  72. boost::unique_lock<boost::mutex> lk(mutex_);
  73. return (count_ == 0);
  74. }
  75. /// try to wait for a specified amount of time is elapsed.
  76. /// @return whether there is a timeout or not.
  77. template <class Rep, class Period>
  78. cv_status wait_for(const chrono::duration<Rep, Period>& rel_time)
  79. {
  80. boost::unique_lock<boost::mutex> lk(mutex_);
  81. if (count_ == 0) return cv_status::no_timeout;
  82. std::size_t generation(generation_);
  83. return cond_.wait_for(lk, rel_time, detail::not_equal(generation, generation_))
  84. ? cv_status::no_timeout
  85. : cv_status::timeout;
  86. }
  87. /// try to wait until the specified time_point is reached
  88. /// @return whether there were a timeout or not.
  89. template <class Clock, class Duration>
  90. cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time)
  91. {
  92. boost::unique_lock<boost::mutex> lk(mutex_);
  93. if (count_ == 0) return cv_status::no_timeout;
  94. std::size_t generation(generation_);
  95. return cond_.wait_until(lk, abs_time, detail::not_equal(generation, generation_))
  96. ? cv_status::no_timeout
  97. : cv_status::timeout;
  98. }
  99. /// Decrement the count and notify anyone waiting if we reach zero.
  100. /// @Requires count must be greater than 0
  101. void count_down()
  102. {
  103. boost::unique_lock<boost::mutex> lk(mutex_);
  104. count_down(lk);
  105. }
  106. /// Effect: Decrement the count if it is > 0 and notify anyone waiting if we reached zero.
  107. /// Returns: true if count_ was 0 or reached 0.
  108. bool try_count_down()
  109. {
  110. boost::unique_lock<boost::mutex> lk(mutex_);
  111. return try_count_down(lk);
  112. }
  113. void signal()
  114. {
  115. count_down();
  116. }
  117. /// Decrement the count and notify anyone waiting if we reach zero.
  118. /// Blocks until the latch has counted down to zero.
  119. /// @Requires count must be greater than 0
  120. void count_down_and_wait()
  121. {
  122. boost::unique_lock<boost::mutex> lk(mutex_);
  123. std::size_t generation(generation_);
  124. if (count_down(lk))
  125. {
  126. return;
  127. }
  128. cond_.wait(lk, detail::not_equal(generation, generation_));
  129. }
  130. void sync()
  131. {
  132. count_down_and_wait();
  133. }
  134. /// Reset the counter
  135. /// #Requires This method may only be invoked when there are no other threads currently inside the count_down_and_wait() method.
  136. void reset(std::size_t count)
  137. {
  138. boost::lock_guard<boost::mutex> lk(mutex_);
  139. //BOOST_ASSERT(count_ == 0);
  140. count_ = count;
  141. }
  142. private:
  143. mutex mutex_;
  144. condition_variable cond_;
  145. std::size_t count_;
  146. std::size_t generation_;
  147. };
  148. } // namespace boost
  149. #include <boost/config/abi_suffix.hpp>
  150. #endif