latch.hpp 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. #ifndef BOOST_COMPAT_LATCH_HPP_INCLUDED
  2. #define BOOST_COMPAT_LATCH_HPP_INCLUDED
  3. // Copyright 2023 Peter Dimov.
  4. // Copyright 2023 Christian Mazakas.
  5. // Distributed under the Boost Software License, Version 1.0.
  6. // https://www.boost.org/LICENSE_1_0.txt
  7. #include <boost/assert.hpp>
  8. #include <climits>
  9. #include <condition_variable>
  10. #include <mutex>
  11. namespace boost
  12. {
  13. namespace compat
  14. {
  15. class latch {
  16. private:
  17. std::ptrdiff_t n_;
  18. mutable std::mutex m_;
  19. mutable std::condition_variable cv_;
  20. public:
  21. explicit latch(std::ptrdiff_t expected) : n_{expected}, m_{}, cv_{} {
  22. BOOST_ASSERT(n_ >= 0);
  23. BOOST_ASSERT(n_ <= max());
  24. }
  25. latch(latch const &) = delete;
  26. latch &operator=(latch const &) = delete;
  27. ~latch() = default;
  28. void count_down(std::ptrdiff_t n = 1) {
  29. std::unique_lock<std::mutex> lk(m_);
  30. count_down_and_notify(lk, n);
  31. }
  32. bool try_wait() const noexcept {
  33. std::unique_lock<std::mutex> lk(m_);
  34. return is_ready();
  35. }
  36. void wait() const {
  37. std::unique_lock<std::mutex> lk(m_);
  38. wait_impl(lk);
  39. }
  40. void arrive_and_wait(std::ptrdiff_t n = 1) {
  41. std::unique_lock<std::mutex> lk(m_);
  42. bool should_wait = count_down_and_notify(lk, n);
  43. if (should_wait) {
  44. wait_impl(lk);
  45. }
  46. }
  47. static constexpr std::ptrdiff_t max() noexcept { return PTRDIFF_MAX; }
  48. private:
  49. bool is_ready() const { return n_ == 0; }
  50. bool count_down_and_notify(std::unique_lock<std::mutex> &lk,
  51. std::ptrdiff_t n) {
  52. BOOST_ASSERT(n <= n_);
  53. n_ -= n;
  54. if (n_ == 0) {
  55. lk.unlock();
  56. cv_.notify_all();
  57. return false;
  58. }
  59. return true;
  60. }
  61. void wait_impl(std::unique_lock<std::mutex> &lk) const {
  62. cv_.wait(lk, [this] { return this->is_ready(); });
  63. }
  64. };
  65. } // namespace compat
  66. } // namespace boost
  67. #endif // #ifndef BOOST_COMPAT_LATCH_HPP_INCLUDED