wait_for_any.hpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. // (C) Copyright 2008-10 Anthony Williams
  2. // (C) Copyright 2011-2015 Vicente J. Botet Escriba
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See
  5. // accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. #ifndef BOOST_THREAD_FUTURES_WAIT_FOR_ANY_HPP
  8. #define BOOST_THREAD_FUTURES_WAIT_FOR_ANY_HPP
  9. #include <boost/thread/detail/config.hpp>
  10. #include <boost/thread/detail/move.hpp>
  11. #include <boost/thread/futures/is_future_type.hpp>
  12. #include <boost/thread/lock_algorithms.hpp>
  13. #include <boost/thread/mutex.hpp>
  14. #include <boost/thread/condition_variable.hpp>
  15. #include <boost/core/enable_if.hpp>
  16. #include <boost/next_prior.hpp>
  17. #include <boost/scoped_array.hpp>
  18. #include <iterator>
  19. #include <vector>
  20. namespace boost
  21. {
  22. namespace detail
  23. {
  24. template <class Future>
  25. class waiter_for_any_in_seq
  26. {
  27. struct registered_waiter;
  28. typedef std::vector<int>::size_type count_type;
  29. struct registered_waiter
  30. {
  31. typedef Future future_type;
  32. future_type* future_;
  33. typedef typename Future::notify_when_ready_handle notify_when_ready_handle;
  34. notify_when_ready_handle handle;
  35. count_type index;
  36. registered_waiter(future_type & a_future,
  37. notify_when_ready_handle handle_, count_type index_) :
  38. future_(&a_future), handle(handle_), index(index_)
  39. {
  40. }
  41. };
  42. struct all_futures_lock
  43. {
  44. #ifdef _MANAGED
  45. typedef std::ptrdiff_t count_type_portable;
  46. #else
  47. typedef count_type count_type_portable;
  48. #endif
  49. count_type_portable count;
  50. boost::scoped_array<boost::unique_lock<boost::mutex> > locks;
  51. all_futures_lock(std::vector<registered_waiter>& waiters) :
  52. count(waiters.size()), locks(new boost::unique_lock<boost::mutex>[count])
  53. {
  54. for (count_type_portable i = 0; i < count; ++i)
  55. {
  56. locks[i] = BOOST_THREAD_MAKE_RV_REF(boost::unique_lock<boost::mutex>(waiters[i].future_->mutex()));
  57. }
  58. }
  59. void lock()
  60. {
  61. boost::lock(locks.get(), locks.get() + count);
  62. }
  63. void unlock()
  64. {
  65. for (count_type_portable i = 0; i < count; ++i)
  66. {
  67. locks[i].unlock();
  68. }
  69. }
  70. };
  71. boost::condition_variable_any cv;
  72. std::vector<registered_waiter> waiters_;
  73. count_type future_count;
  74. public:
  75. waiter_for_any_in_seq() :
  76. future_count(0)
  77. {
  78. }
  79. template <typename F>
  80. void add(F& f)
  81. {
  82. if (f.valid())
  83. {
  84. registered_waiter waiter(f, f.notify_when_ready(cv), future_count);
  85. try
  86. {
  87. waiters_.push_back(waiter);
  88. }
  89. catch (...)
  90. {
  91. f.future_->unnotify_when_ready(waiter.handle);
  92. throw;
  93. }
  94. ++future_count;
  95. }
  96. }
  97. #ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
  98. template <typename F1, typename ... Fs>
  99. void add(F1& f1, Fs&... fs)
  100. {
  101. add(f1);
  102. add(fs...);
  103. }
  104. #endif
  105. count_type wait()
  106. {
  107. all_futures_lock lk(waiters_);
  108. for (;;)
  109. {
  110. for (count_type i = 0; i < waiters_.size(); ++i)
  111. {
  112. if (waiters_[i].future_->is_ready(lk.locks[i]))
  113. {
  114. return waiters_[i].index;
  115. }
  116. }
  117. cv.wait(lk);
  118. }
  119. }
  120. ~waiter_for_any_in_seq()
  121. {
  122. for (count_type i = 0; i < waiters_.size(); ++i)
  123. {
  124. waiters_[i].future_->unnotify_when_ready(waiters_[i].handle);
  125. }
  126. }
  127. };
  128. }
  129. template <typename Iterator>
  130. typename boost::disable_if<is_future_type<Iterator> , Iterator>::type wait_for_any(Iterator begin, Iterator end)
  131. {
  132. if (begin == end) return end;
  133. detail::waiter_for_any_in_seq<typename std::iterator_traits<Iterator>::value_type> waiter;
  134. for (Iterator current = begin; current != end; ++current)
  135. {
  136. waiter.add(*current);
  137. }
  138. return boost::next(begin, waiter.wait());
  139. }
  140. }
  141. #endif // header