serial_executor_cont.hpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // Copyright (C) 2015 Vicente J. Botet Escriba
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. //
  6. // 2013/11 Vicente J. Botet Escriba
  7. // first implementation of a simple serial scheduler.
  8. #ifndef BOOST_THREAD_SERIAL_EXECUTOR_CONT_HPP
  9. #define BOOST_THREAD_SERIAL_EXECUTOR_CONT_HPP
  10. #include <boost/thread/detail/config.hpp>
  11. #if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
  12. #include <exception> // std::terminate
  13. #include <boost/throw_exception.hpp>
  14. #include <boost/thread/detail/delete.hpp>
  15. #include <boost/thread/detail/move.hpp>
  16. #include <boost/thread/concurrent_queues/sync_queue.hpp>
  17. #include <boost/thread/executors/work.hpp>
  18. #include <boost/thread/executors/generic_executor_ref.hpp>
  19. #include <boost/thread/mutex.hpp>
  20. #include <boost/thread/future.hpp>
  21. #include <boost/thread/scoped_thread.hpp>
  22. #include <boost/thread/lock_guard.hpp>
  23. #include <boost/config/abi_prefix.hpp>
  24. namespace boost
  25. {
  26. namespace executors
  27. {
  28. class serial_executor_cont
  29. {
  30. public:
  31. /// type-erasure to store the works to do
  32. typedef executors::work work;
  33. private:
  34. generic_executor_ref ex_;
  35. BOOST_THREAD_FUTURE<void> fut_; // protected by mtx_
  36. bool closed_; // protected by mtx_
  37. mutex mtx_;
  38. struct continuation {
  39. work task;
  40. template <class X>
  41. struct result {
  42. typedef void type;
  43. };
  44. continuation(BOOST_THREAD_RV_REF(work) tsk)
  45. : task(boost::move(tsk)) {}
  46. void operator()(BOOST_THREAD_FUTURE<void> f)
  47. {
  48. try {
  49. task();
  50. } catch (...) {
  51. std::terminate();
  52. }
  53. }
  54. };
  55. bool closed(lock_guard<mutex>&) const
  56. {
  57. return closed_;
  58. }
  59. public:
  60. /**
  61. * \par Returns
  62. * The underlying executor wrapped on a generic executor reference.
  63. */
  64. generic_executor_ref& underlying_executor() BOOST_NOEXCEPT { return ex_; }
  65. /// serial_executor_cont is not copyable.
  66. BOOST_THREAD_NO_COPYABLE(serial_executor_cont)
  67. /**
  68. * \b Effects: creates a serial executor that runs closures in fifo order using one the associated executor.
  69. *
  70. * \b Throws: Whatever exception is thrown while initializing the needed resources.
  71. *
  72. * \b Notes:
  73. * * The lifetime of the associated executor must outlive the serial executor.
  74. * * The current implementation doesn't support submission from synchronous continuation, that is,
  75. * - the executor must execute the continuation asynchronously or
  76. * - the continuation can not submit to this serial executor.
  77. */
  78. template <class Executor>
  79. serial_executor_cont(Executor& ex)
  80. : ex_(ex), fut_(make_ready_future()), closed_(false)
  81. {
  82. }
  83. /**
  84. * \b Effects: Destroys the thread pool.
  85. *
  86. * \b Synchronization: The completion of all the closures happen before the completion of the \c serial_executor_cont destructor.
  87. */
  88. ~serial_executor_cont()
  89. {
  90. // signal to the worker thread that there will be no more submissions.
  91. close();
  92. }
  93. /**
  94. * \b Effects: close the \c serial_executor_cont for submissions.
  95. * The loop will work until there is no more closures to run.
  96. */
  97. void close()
  98. {
  99. lock_guard<mutex> lk(mtx_);
  100. closed_ = true;;
  101. }
  102. /**
  103. * \b Returns: whether the pool is closed for submissions.
  104. */
  105. bool closed()
  106. {
  107. lock_guard<mutex> lk(mtx_);
  108. return closed(lk);
  109. }
  110. /**
  111. * Effects: none.
  112. * Returns: always false.
  113. * Throws: No.
  114. * Remark: A serial executor can not execute one of its pending tasks as the tasks depends on the other tasks.
  115. */
  116. bool try_executing_one()
  117. {
  118. return false;
  119. }
  120. /**
  121. * \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
  122. *
  123. * \b Effects: The specified \c closure will be scheduled for execution after the last submitted closure finish.
  124. * If the invoked closure throws an exception the \c serial_executor_cont will call \c std::terminate, as is the case with threads.
  125. *
  126. * \b Throws: \c sync_queue_is_closed if the executor is closed.
  127. * Whatever exception that can be throw while storing the closure.
  128. *
  129. */
  130. #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  131. template <typename Closure>
  132. void submit(Closure & closure)
  133. {
  134. lock_guard<mutex> lk(mtx_);
  135. if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
  136. fut_ = fut_.then(ex_, continuation(work(closure)));
  137. }
  138. #endif
  139. void submit(void (*closure)())
  140. {
  141. lock_guard<mutex> lk(mtx_);
  142. if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
  143. fut_ = fut_.then(ex_, continuation(work(closure)));
  144. }
  145. template <typename Closure>
  146. void submit(BOOST_THREAD_FWD_REF(Closure) closure)
  147. {
  148. lock_guard<mutex> lk(mtx_);
  149. if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
  150. fut_ = fut_.then(ex_, continuation(work(boost::forward<Closure>(closure))));
  151. }
  152. };
  153. }
  154. using executors::serial_executor_cont;
  155. }
  156. #include <boost/config/abi_suffix.hpp>
  157. #endif
  158. #endif