Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-15 10:09:32

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