Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 10:01:11

0001 // Copyright (C) 2013,2014 Vicente J. Botet Escriba
0002 //
0003 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
0004 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0005 //
0006 // 2013/11 Vicente J. Botet Escriba
0007 //    first implementation of a simple user scheduler.
0008 // 2013/11 Vicente J. Botet Escriba
0009 //    rename loop_executor.
0010 
0011 #ifndef BOOST_THREAD_EXECUTORS_LOOP_EXECUTOR_HPP
0012 #define BOOST_THREAD_EXECUTORS_LOOP_EXECUTOR_HPP
0013 
0014 #include <boost/thread/detail/config.hpp>
0015 
0016 #if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
0017 
0018 #include <boost/thread/detail/delete.hpp>
0019 #include <boost/thread/detail/move.hpp>
0020 #include <boost/thread/concurrent_queues/sync_queue.hpp>
0021 #include <boost/thread/executors/work.hpp>
0022 #include <boost/assert.hpp>
0023 
0024 #include <boost/config/abi_prefix.hpp>
0025 
0026 namespace boost
0027 {
0028 namespace executors
0029 {
0030 
0031   class loop_executor
0032   {
0033   public:
0034     /// type-erasure to store the works to do
0035     typedef  executors::work work;
0036   private:
0037     /// the thread safe work queue
0038     concurrent::sync_queue<work > work_queue;
0039 
0040   public:
0041     /**
0042      * Effects: try to execute one task.
0043      * Returns: whether a task has been executed.
0044      * Throws: whatever the current task constructor throws or the task() throws.
0045      */
0046     bool try_executing_one()
0047     {
0048       return execute_one(/*wait:*/false);
0049     }
0050 
0051   private:
0052     /**
0053      * Effects: Execute one task.
0054      * Remark: If wait is true, waits until a task is available or the executor
0055      *         is closed. If wait is false, returns false immediately if no
0056      *         task is available.
0057      * Returns: whether a task has been executed (if wait is true, only returns false if closed).
0058      * Throws: whatever the current task constructor throws or the task() throws.
0059      */
0060     bool execute_one(bool wait)
0061     {
0062       work task;
0063       try
0064       {
0065         queue_op_status status = wait ?
0066           work_queue.wait_pull(task) :
0067           work_queue.try_pull(task);
0068         if (status == queue_op_status::success)
0069         {
0070           task();
0071           return true;
0072         }
0073         BOOST_ASSERT(!wait || status == queue_op_status::closed);
0074         return false;
0075       }
0076       catch (...)
0077       {
0078         std::terminate();
0079         //return false;
0080       }
0081     }
0082 
0083   public:
0084     /// loop_executor is not copyable.
0085     BOOST_THREAD_NO_COPYABLE(loop_executor)
0086 
0087     /**
0088      * \b Effects: creates a thread pool that runs closures using one of its closure-executing methods.
0089      *
0090      * \b Throws: Whatever exception is thrown while initializing the needed resources.
0091      */
0092     loop_executor()
0093     {
0094     }
0095     /**
0096      * \b Effects: Destroys the thread pool.
0097      *
0098      * \b Synchronization: The completion of all the closures happen before the completion of the \c loop_executor destructor.
0099      */
0100     ~loop_executor()
0101     {
0102       // signal to all the worker thread that there will be no more submissions.
0103       close();
0104     }
0105 
0106     /**
0107      * The main loop of the worker thread
0108      */
0109     void loop()
0110     {
0111       while (execute_one(/*wait:*/true))
0112       {
0113       }
0114       BOOST_ASSERT(closed());
0115       while (try_executing_one())
0116       {
0117       }
0118     }
0119 
0120     /**
0121      * \b Effects: close the \c loop_executor for submissions.
0122      * The loop will work until there is no more closures to run.
0123      */
0124     void close()
0125     {
0126       work_queue.close();
0127     }
0128 
0129     /**
0130      * \b Returns: whether the pool is closed for submissions.
0131      */
0132     bool closed()
0133     {
0134       return work_queue.closed();
0135     }
0136 
0137     /**
0138      * \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
0139      *
0140      * \b Effects: The specified \c closure will be scheduled for execution at some point in the future.
0141      * If invoked closure throws an exception the \c loop_executor will call \c std::terminate, as is the case with threads.
0142      *
0143      * \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables.
0144      *
0145      * \b Throws: \c sync_queue_is_closed if the thread pool is closed.
0146      * Whatever exception that can be throw while storing the closure.
0147      */
0148     void submit(BOOST_THREAD_RV_REF(work) closure)  {
0149       work_queue.push(boost::move(closure));
0150     }
0151 
0152 #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
0153     template <typename Closure>
0154     void submit(Closure & closure)
0155     {
0156       submit(work(closure));
0157    }
0158 #endif
0159 
0160     void submit(void (*closure)())
0161     {
0162       submit(work(closure));
0163     }
0164 
0165     template <typename Closure>
0166     void submit(BOOST_THREAD_FWD_REF(Closure) closure)
0167     {
0168       //work_queue.push(work(boost::forward<Closure>(closure)));
0169       work w((boost::forward<Closure>(closure)));
0170       submit(boost::move(w));
0171     }
0172 
0173     /**
0174      * \b Requires: This must be called from an scheduled task.
0175      *
0176      * \b Effects: reschedule functions until pred()
0177      */
0178     template <typename Pred>
0179     bool reschedule_until(Pred const& pred)
0180     {
0181       do {
0182         if ( ! try_executing_one())
0183         {
0184           return false;
0185         }
0186       } while (! pred());
0187       return true;
0188     }
0189 
0190     /**
0191      * run queued closures
0192      */
0193     void run_queued_closures()
0194     {
0195       sync_queue<work>::underlying_queue_type q = work_queue.underlying_queue();
0196       while (! q.empty())
0197       {
0198         work& task = q.front();
0199         task();
0200         q.pop_front();
0201       }
0202     }
0203 
0204   };
0205 }
0206 using executors::loop_executor;
0207 
0208 }
0209 
0210 #include <boost/config/abi_suffix.hpp>
0211 #endif
0212 
0213 #endif