yat/utility/Scheduler.h

Code
Comments
Other
Rev Date Author Line
3346 06 Nov 14 peter 1 #ifndef theplu_yat_utility_scheduler
3346 06 Nov 14 peter 2 #define theplu_yat_utility_scheduler
3346 06 Nov 14 peter 3
3346 06 Nov 14 peter 4 // $Id$
3346 06 Nov 14 peter 5
3346 06 Nov 14 peter 6 /*
3855 02 Jan 20 peter 7   Copyright (C) 2014, 2015, 2016, 2017, 2019, 2020 Peter Johansson
3346 06 Nov 14 peter 8
3346 06 Nov 14 peter 9   This file is part of the yat library, http://dev.thep.lu.se/yat
3346 06 Nov 14 peter 10
3346 06 Nov 14 peter 11   The yat library is free software; you can redistribute it and/or
3346 06 Nov 14 peter 12   modify it under the terms of the GNU General Public License as
3346 06 Nov 14 peter 13   published by the Free Software Foundation; either version 3 of the
3346 06 Nov 14 peter 14   License, or (at your option) any later version.
3346 06 Nov 14 peter 15
3346 06 Nov 14 peter 16   The yat library is distributed in the hope that it will be useful,
3346 06 Nov 14 peter 17   but WITHOUT ANY WARRANTY; without even the implied warranty of
3346 06 Nov 14 peter 18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3346 06 Nov 14 peter 19   General Public License for more details.
3346 06 Nov 14 peter 20
3346 06 Nov 14 peter 21   You should have received a copy of the GNU General Public License
3346 06 Nov 14 peter 22   along with yat. If not, see <http://www.gnu.org/licenses/>.
3346 06 Nov 14 peter 23 */
3346 06 Nov 14 peter 24
3402 31 Mar 15 peter 25 #include "PriorityQueue.h"
3346 06 Nov 14 peter 26 #include "Queue.h"
3346 06 Nov 14 peter 27
3405 06 Apr 15 peter 28 #include <boost/exception_ptr.hpp>
3346 06 Nov 14 peter 29 #include <boost/shared_ptr.hpp>
3346 06 Nov 14 peter 30
3848 23 Sep 19 peter 31 #include <list>
3948 20 Jul 20 peter 32 #include <mutex>
3346 06 Nov 14 peter 33 #include <set>
3948 20 Jul 20 peter 34 #include <thread>
3848 23 Sep 19 peter 35 #include <vector>
3346 06 Nov 14 peter 36
3346 06 Nov 14 peter 37 namespace theplu {
3346 06 Nov 14 peter 38 namespace yat {
3346 06 Nov 14 peter 39 namespace utility {
3346 06 Nov 14 peter 40
3346 06 Nov 14 peter 41   /**
3346 06 Nov 14 peter 42      \brief Handle a number of jobs and send them to threads
3346 06 Nov 14 peter 43
3346 06 Nov 14 peter 44      Scheduler starts a (user defined) number of threads and handles a
3346 06 Nov 14 peter 45      series of Jobs. The Jobs can have dependencies, such that Job X
3346 06 Nov 14 peter 46      must finish before Job Y can run, and the Scheduler takes care of
3402 31 Mar 15 peter 47      these dependencies. Here is a small code example in which two
3346 06 Nov 14 peter 48      threads are used to process the four jobs, \c MyJob. The jobs
3346 06 Nov 14 peter 49      have a dependency that job4 can not run until the three first
3346 06 Nov 14 peter 50      jobs have completed.
3346 06 Nov 14 peter 51
3346 06 Nov 14 peter 52      \code
3346 06 Nov 14 peter 53
3346 06 Nov 14 peter 54      Scheduler scheduler(2);
3346 06 Nov 14 peter 55      boost::shared_ptr<MyJob> job1(new MyJob("Hello"));
3401 31 Mar 15 peter 56      boost::shared_ptr<MyJob> job2(new MyJob(" "));
3346 06 Nov 14 peter 57      boost::shared_ptr<MyJob> job3(new MyJob("World"));
3346 06 Nov 14 peter 58      boost::shared_ptr<MyJob> job4(new MyJob("\n"));
3401 31 Mar 15 peter 59      scheduler.add_dependency(job4, job1);
3401 31 Mar 15 peter 60      scheduler.add_dependency(job4, job2);
3401 31 Mar 15 peter 61      scheduler.add_dependency(job4, job3);
3346 06 Nov 14 peter 62      scheduler.submit(job4);
3402 31 Mar 15 peter 63      scheduler.wait();
3346 06 Nov 14 peter 64
3346 06 Nov 14 peter 65      \endcode
3402 31 Mar 15 peter 66
3402 31 Mar 15 peter 67      The Scheduler sends jobs to the workers taking into account
3402 31 Mar 15 peter 68      dependencies, priorities and the order in which the Scheduler has
3683 22 Aug 17 peter 69      seen the Jobs. If the Jobs that are ready to run, i.e., all jobs
3683 22 Aug 17 peter 70      it depends on have completed, the Scheduler choose the Job with
3402 31 Mar 15 peter 71      highest priority. If two Jobs have the same priority, the
3402 31 Mar 15 peter 72      Scheduler sends them in the order of appearance, i.e., if the
3402 31 Mar 15 peter 73      Scheduler saw Job X before Job Y, Job X is run before Job X.
3402 31 Mar 15 peter 74
3406 07 Apr 15 peter 75      \note In the current implementation all submitted jobs have
3406 07 Apr 15 peter 76      to be completed before the Scheduler goes out of scope, which can
3406 07 Apr 15 peter 77      be accomplished by calling wait() or interrupt().
3406 07 Apr 15 peter 78
3828 23 Jul 19 peter 79      \note Prior version 0.17 the Scheduler could not be recycled, i.e.,
3828 23 Jul 19 peter 80      if wait(void) or interruped(void) had been called, the behaviour of
3828 23 Jul 19 peter 81      submit() was undefined.
3406 07 Apr 15 peter 82
3402 31 Mar 15 peter 83      \since New in yat 0.13
3346 06 Nov 14 peter 84    */
3346 06 Nov 14 peter 85   class Scheduler
3346 06 Nov 14 peter 86   {
3346 06 Nov 14 peter 87   public:
3346 06 Nov 14 peter 88     /**
3346 06 Nov 14 peter 89        Base class that defines the interface for a Job
3346 06 Nov 14 peter 90      */
3346 06 Nov 14 peter 91     class Job
3346 06 Nov 14 peter 92     {
3346 06 Nov 14 peter 93     public:
3346 06 Nov 14 peter 94       /**
3346 06 Nov 14 peter 95          \brief constructor
3848 23 Sep 19 peter 96          \param prio sets the priority. Jobs with greater priority are
3848 23 Sep 19 peter 97          run before jobs with lower priority (when possible).
3346 06 Nov 14 peter 98        */
3402 31 Mar 15 peter 99       explicit Job(unsigned int prio=0);
3346 06 Nov 14 peter 100
3346 06 Nov 14 peter 101       /**
3346 06 Nov 14 peter 102          \brief destructor
3346 06 Nov 14 peter 103        */
3346 06 Nov 14 peter 104       virtual ~Job(void);
3346 06 Nov 14 peter 105
3346 06 Nov 14 peter 106       /**
3402 31 Mar 15 peter 107          Jobs with greater priority are run before Jobs with less priority.
3402 31 Mar 15 peter 108        */
3402 31 Mar 15 peter 109       unsigned int priority(void) const;
3402 31 Mar 15 peter 110
3402 31 Mar 15 peter 111       /**
3346 06 Nov 14 peter 112          This function defines the work done in thread.
3346 06 Nov 14 peter 113        */
3346 06 Nov 14 peter 114       virtual void operator()(void)=0;
3346 06 Nov 14 peter 115     private:
3346 06 Nov 14 peter 116       friend class Scheduler;
3681 22 Aug 17 peter 117       friend class JobHandler;
3853 01 Jan 20 peter 118       void add_prerequisite(const boost::shared_ptr<Job>&,
3948 20 Jul 20 peter 119                             const std::unique_lock<std::mutex>& lock);
3681 22 Aug 17 peter 120       // \brief remove job from list of prerequisite
3681 22 Aug 17 peter 121       // \return number of prerequisite (after removal)
3853 01 Jan 20 peter 122       size_t remove_prerequisite(const boost::shared_ptr<Job>&,
3948 20 Jul 20 peter 123                                  const std::unique_lock<std::mutex>& lock);
3346 06 Nov 14 peter 124       // set of jobs that have to finish before this can run
3401 31 Mar 15 peter 125       std::set<boost::shared_ptr<Job> > prerequisite_;
3853 01 Jan 20 peter 126       // avoid accessing prerequisite_ directly but rather via
3853 01 Jan 20 peter 127       // functions below passing Dependency::Lock
3853 01 Jan 20 peter 128       std::set<boost::shared_ptr<Job> >&
3948 20 Jul 20 peter 129       prerequisite(const std::unique_lock<std::mutex>& lock);
3853 01 Jan 20 peter 130       const std::set<boost::shared_ptr<Job> >&
3948 20 Jul 20 peter 131       prerequisite(const std::unique_lock<std::mutex>& lock) const;
3681 22 Aug 17 peter 132       // - pristine is what it says
3681 22 Aug 17 peter 133       // - prepared - job has been either submitted directly a job that
3681 22 Aug 17 peter 134       // depends on job has been submitted et.c.
3681 22 Aug 17 peter 135       // - running - job has been sent to queue for workers to chew on
3681 22 Aug 17 peter 136       // - completed - job has returned
3853 01 Jan 20 peter 137       enum status_type { pristine, prepared, running, completed};
3853 01 Jan 20 peter 138       status_type status_;
3948 20 Jul 20 peter 139       status_type status(const std::unique_lock<std::mutex>& lock) const;
3948 20 Jul 20 peter 140       void status(const std::unique_lock<std::mutex>& lock, status_type s);
3402 31 Mar 15 peter 141       unsigned priority_;
3402 31 Mar 15 peter 142       unsigned id_;
3405 06 Apr 15 peter 143       boost::exception_ptr error_;
3346 06 Nov 14 peter 144     }; // end class Job
3346 06 Nov 14 peter 145
3346 06 Nov 14 peter 146     /**
3346 06 Nov 14 peter 147        \brief constructor
3346 06 Nov 14 peter 148
3346 06 Nov 14 peter 149        \param threads number of threads that are used
3346 06 Nov 14 peter 150      */
3346 06 Nov 14 peter 151     Scheduler(unsigned int threads);
3346 06 Nov 14 peter 152
3346 06 Nov 14 peter 153     /**
3401 31 Mar 15 peter 154        \brief add a dependency rule
3401 31 Mar 15 peter 155
3401 31 Mar 15 peter 156        Add a dependency that Job \a prerequisite has to complete
3401 31 Mar 15 peter 157        before Job \a job is run.
3681 22 Aug 17 peter 158
3681 22 Aug 17 peter 159        Note, job cannot have been submitted, neither directly or
3681 22 Aug 17 peter 160        by being prerequisite of a submitted job.
3401 31 Mar 15 peter 161      */
3401 31 Mar 15 peter 162     void add_dependency(boost::shared_ptr<Job> job,
3401 31 Mar 15 peter 163                         boost::shared_ptr<Job> prerequisite);
3405 06 Apr 15 peter 164     /**
3405 06 Apr 15 peter 165        \brief interrrupt all jobs
3405 06 Apr 15 peter 166      */
3405 06 Apr 15 peter 167     void interrupt(void);
3401 31 Mar 15 peter 168
3401 31 Mar 15 peter 169     /**
3679 18 Aug 17 peter 170        \return Number of jobs that are either running or queued, i.e.,
3679 18 Aug 17 peter 171        jobs that are waiting for a dependency are not counted.
3679 18 Aug 17 peter 172
3679 18 Aug 17 peter 173        \since New in yat 0.15
3679 18 Aug 17 peter 174      */
3679 18 Aug 17 peter 175     size_t jobs(void) const;
3679 18 Aug 17 peter 176
3679 18 Aug 17 peter 177     /**
3348 13 Nov 14 peter 178        \brief submit a \a job to Scheduler
3349 13 Nov 14 peter 179
3349 13 Nov 14 peter 180        If \a job depends on other jobs, they are also submitted to the
3349 13 Nov 14 peter 181        Scheduler.
3346 06 Nov 14 peter 182      */
3681 22 Aug 17 peter 183     void submit(const boost::shared_ptr<Job>& job);
3346 06 Nov 14 peter 184
3346 06 Nov 14 peter 185     /**
3826 18 Jul 19 peter 186        \return number of threads used
3826 18 Jul 19 peter 187
3826 18 Jul 19 peter 188        \since new in yat 0.17
3826 18 Jul 19 peter 189      */
3848 23 Sep 19 peter 190     unsigned int threads(void) const;
3826 18 Jul 19 peter 191
3826 18 Jul 19 peter 192     /**
3848 23 Sep 19 peter 193        Change number of threads used. If \a n is greater than current
3848 23 Sep 19 peter 194        number of threads, additional threads are launched. If \a n is
3848 23 Sep 19 peter 195        smaller than current number used, a number of threads are
3848 23 Sep 19 peter 196        notified to end after the current job has been completed. A
3848 23 Sep 19 peter 197        decrease in threads therefore does not have an immediate
3848 23 Sep 19 peter 198        effect.
3848 23 Sep 19 peter 199
3848 23 Sep 19 peter 200        \since new in yat 0.17
3848 23 Sep 19 peter 201      */
3848 23 Sep 19 peter 202     void threads(unsigned int n);
3848 23 Sep 19 peter 203
3848 23 Sep 19 peter 204     /**
3348 13 Nov 14 peter 205        \brief wait for all jobs to finish
3346 06 Nov 14 peter 206      */
3348 13 Nov 14 peter 207     void wait(void);
3346 06 Nov 14 peter 208
3346 06 Nov 14 peter 209   private:
3848 23 Sep 19 peter 210     // forward declaration
3848 23 Sep 19 peter 211     class JobHandler;
3848 23 Sep 19 peter 212
3402 31 Mar 15 peter 213     typedef boost::shared_ptr<Scheduler::Job> JobPtr;
3402 31 Mar 15 peter 214
3848 23 Sep 19 peter 215     class Messenger
3848 23 Sep 19 peter 216     {
3848 23 Sep 19 peter 217     public:
3848 23 Sep 19 peter 218       virtual void operator()(JobHandler& handler)=0;
3848 23 Sep 19 peter 219     };
3848 23 Sep 19 peter 220
3848 23 Sep 19 peter 221     typedef boost::shared_ptr<Messenger> MessengerPtr;
3848 23 Sep 19 peter 222     typedef Queue<MessengerPtr> MessengerQueue;
3848 23 Sep 19 peter 223
3848 23 Sep 19 peter 224     class JobMessenger : public Messenger
3848 23 Sep 19 peter 225     {
3848 23 Sep 19 peter 226     public:
3848 23 Sep 19 peter 227       JobMessenger(const JobPtr&);
3848 23 Sep 19 peter 228       void operator()(JobHandler& handler);
3848 23 Sep 19 peter 229     private:
3848 23 Sep 19 peter 230       JobPtr job_;
3848 23 Sep 19 peter 231     };
3848 23 Sep 19 peter 232
3848 23 Sep 19 peter 233
3848 23 Sep 19 peter 234     class SchedulerIsWaiting : public Messenger
3848 23 Sep 19 peter 235     {
3848 23 Sep 19 peter 236     public:
3848 23 Sep 19 peter 237       void operator()(JobHandler& handler);
3848 23 Sep 19 peter 238     };
3848 23 Sep 19 peter 239
3848 23 Sep 19 peter 240
3848 23 Sep 19 peter 241     class InterruptWorkers : public Messenger
3848 23 Sep 19 peter 242     {
3848 23 Sep 19 peter 243     public:
3848 23 Sep 19 peter 244       void operator()(JobHandler& handler);
3848 23 Sep 19 peter 245     };
3848 23 Sep 19 peter 246
3848 23 Sep 19 peter 247
3848 23 Sep 19 peter 248     // Class used to change number of workers
3848 23 Sep 19 peter 249     class WorkForceSizer : public Messenger
3848 23 Sep 19 peter 250     {
3848 23 Sep 19 peter 251     public:
3848 23 Sep 19 peter 252       void operator()(JobHandler& handler);
3848 23 Sep 19 peter 253     };
3848 23 Sep 19 peter 254
3848 23 Sep 19 peter 255
3402 31 Mar 15 peter 256     struct LowerPriority
3402 31 Mar 15 peter 257     {
3402 31 Mar 15 peter 258       bool operator()(const JobPtr& lhs, const JobPtr& rhs) const;
3402 31 Mar 15 peter 259     };
3402 31 Mar 15 peter 260
3402 31 Mar 15 peter 261     // some typedefs for convenience
3402 31 Mar 15 peter 262     typedef PriorityQueue<JobPtr, LowerPriority> JobQueue;
3402 31 Mar 15 peter 263
3346 06 Nov 14 peter 264     // \internal class that does the job
3346 06 Nov 14 peter 265     //
3346 06 Nov 14 peter 266     // It processes any job that is pushed to the \a queue until a
3346 06 Nov 14 peter 267     // NULL Job shows up which signals that the work is done. When
3346 06 Nov 14 peter 268     // NULL is observed the NULL Job is pushed to the queue so
3346 06 Nov 14 peter 269     // co-workers are notified too.
3346 06 Nov 14 peter 270     class Worker
3346 06 Nov 14 peter 271     {
3346 06 Nov 14 peter 272     public:
3848 23 Sep 19 peter 273       Worker(JobQueue& queue, MessengerQueue& completed);
3346 06 Nov 14 peter 274       void operator()(void);
3346 06 Nov 14 peter 275     private:
3402 31 Mar 15 peter 276       JobQueue& queue_;
3848 23 Sep 19 peter 277       MessengerQueue& completed_;
3346 06 Nov 14 peter 278     }; // end class Worker
3346 06 Nov 14 peter 279
3823 16 Jul 19 peter 280
3853 01 Jan 20 peter 281     class Dependency
3853 01 Jan 20 peter 282     {
3853 01 Jan 20 peter 283     public:
3948 20 Jul 20 peter 284       typedef std::unique_lock<std::mutex> Lock;
3853 01 Jan 20 peter 285
3853 01 Jan 20 peter 286       void add(const JobPtr& child, const JobPtr& parent, const Lock& lock);
3853 01 Jan 20 peter 287       void remove(const JobPtr& parent, const Lock& lock);
3853 01 Jan 20 peter 288       std::vector<JobPtr>& children(const JobPtr& key, const Lock& lock);
3948 20 Jul 20 peter 289       std::mutex& mutex(void);
3853 01 Jan 20 peter 290     private:
3948 20 Jul 20 peter 291       std::mutex mutex_;
3853 01 Jan 20 peter 292
3853 01 Jan 20 peter 293       // job in key has to finish before jobs in vector
3853 01 Jan 20 peter 294       std::map<JobPtr, std::vector<JobPtr> > children_;
3853 01 Jan 20 peter 295
3853 01 Jan 20 peter 296       std::vector<JobPtr> empty_vector_;
3853 01 Jan 20 peter 297     };
3853 01 Jan 20 peter 298
3853 01 Jan 20 peter 299
3823 16 Jul 19 peter 300     class JobHandlerData
3823 16 Jul 19 peter 301     {
3823 16 Jul 19 peter 302     public:
3823 16 Jul 19 peter 303       /// thread-safe class around int
3823 16 Jul 19 peter 304       class Count
3823 16 Jul 19 peter 305       {
3823 16 Jul 19 peter 306       public:
3823 16 Jul 19 peter 307         /// Constructor
3823 16 Jul 19 peter 308         explicit Count(int x=0);
3823 16 Jul 19 peter 309         /// increase value with 1
3823 16 Jul 19 peter 310         void decrement(void);
3823 16 Jul 19 peter 311         /// return value
3823 16 Jul 19 peter 312         int get(void) const;
3823 16 Jul 19 peter 313         /// decrease value with 1
3823 16 Jul 19 peter 314         void increment(void);
3823 16 Jul 19 peter 315         /// modify value
3823 16 Jul 19 peter 316         void set(int x);
3823 16 Jul 19 peter 317       private:
3948 20 Jul 20 peter 318         mutable std::mutex mutex_;
3823 16 Jul 19 peter 319         int x_;
3823 16 Jul 19 peter 320       };
3823 16 Jul 19 peter 321
3848 23 Sep 19 peter 322       JobHandlerData(void);
3823 16 Jul 19 peter 323       Queue<boost::exception_ptr>& error(void) const;
3823 16 Jul 19 peter 324
3853 01 Jan 20 peter 325       Dependency& dependency(void);
3853 01 Jan 20 peter 326       const Dependency& dependency(void) const;
3853 01 Jan 20 peter 327
3848 23 Sep 19 peter 328       const MessengerQueue& messengers(void) const;
3848 23 Sep 19 peter 329       MessengerQueue& messengers(void); //
3848 23 Sep 19 peter 330       const JobQueue& queue(void) const; //
3823 16 Jul 19 peter 331       JobQueue& queue(void);
3823 16 Jul 19 peter 332
3823 16 Jul 19 peter 333       const Count& running_jobs(void) const;
3823 16 Jul 19 peter 334       Count& running_jobs(void);
3823 16 Jul 19 peter 335
3848 23 Sep 19 peter 336       const Count& n_threads(void) const;
3848 23 Sep 19 peter 337       Count& n_threads(void);
3823 16 Jul 19 peter 338     private:
3823 16 Jul 19 peter 339       mutable Queue<boost::exception_ptr> error_;
3848 23 Sep 19 peter 340       MessengerQueue messengers_;
3848 23 Sep 19 peter 341       // This is the queue workers are consuming from.
3823 16 Jul 19 peter 342       JobQueue queue_;
3823 16 Jul 19 peter 343
3948 20 Jul 20 peter 344       std::mutex mutex_;
3853 01 Jan 20 peter 345
3823 16 Jul 19 peter 346       Count running_jobs_;
3823 16 Jul 19 peter 347       Count threads_;
3853 01 Jan 20 peter 348
3853 01 Jan 20 peter 349       Dependency dependency_;
3823 16 Jul 19 peter 350     };
3823 16 Jul 19 peter 351
3823 16 Jul 19 peter 352
3681 22 Aug 17 peter 353     // \internal Class that handles job
3681 22 Aug 17 peter 354     class JobHandler
3681 22 Aug 17 peter 355     {
3681 22 Aug 17 peter 356     public:
3823 16 Jul 19 peter 357       JobHandler(JobHandlerData& data);
3681 22 Aug 17 peter 358
3681 22 Aug 17 peter 359       void operator()(void);
3848 23 Sep 19 peter 360       void create_workers(unsigned int n);
3848 23 Sep 19 peter 361       JobHandlerData& data(void);
3848 23 Sep 19 peter 362       void interrupt_workers(void);
3848 23 Sep 19 peter 363       void kill_workers(void);
3848 23 Sep 19 peter 364       void kill_workers(unsigned int n);
3848 23 Sep 19 peter 365       // If \a job has parent jobs, which need to finish first, update
3848 23 Sep 19 peter 366       // map children_ to reflect that. If all parents have finished,
3848 23 Sep 19 peter 367       // send job to queue.
3848 23 Sep 19 peter 368       void process(JobPtr& job);
3848 23 Sep 19 peter 369       void remove_joined_workers(void);
3848 23 Sep 19 peter 370       void scheduler_is_waiting(bool value);
3848 23 Sep 19 peter 371       unsigned int n_target_workers(void) const;
3848 23 Sep 19 peter 372       void wait_workers(void) const;
3681 22 Aug 17 peter 373     private:
3681 22 Aug 17 peter 374
3681 22 Aug 17 peter 375       // If job is ready to be submitted i.e. all prerequisite have
3681 22 Aug 17 peter 376       // completed, then submit job to queue for workers to chew on.
3853 01 Jan 20 peter 377       void prepare(JobPtr job, const Dependency::Lock& lock);
3681 22 Aug 17 peter 378       // handle jobs returned from worker
3848 23 Sep 19 peter 379       //
3848 23 Sep 19 peter 380       // function called when job has finished and returned from
3848 23 Sep 19 peter 381       // worker. If there are any jobs that depend on \a job, those jobs
3848 23 Sep 19 peter 382       // are notified and if it makes them ready to be processed they
3848 23 Sep 19 peter 383       // are sent to queue.
3853 01 Jan 20 peter 384       void post_process(JobPtr job, const Dependency::Lock& lock);
3681 22 Aug 17 peter 385
3853 01 Jan 20 peter 386       void send2queue(JobPtr& job,
3948 20 Jul 20 peter 387                       const std::unique_lock<std::mutex>& lock);
3823 16 Jul 19 peter 388
3823 16 Jul 19 peter 389       JobHandlerData* data_;
3848 23 Sep 19 peter 390       bool scheduler_is_waiting_;
3848 23 Sep 19 peter 391       unsigned int job_count_;
3848 23 Sep 19 peter 392       void join_workers(void);
3681 22 Aug 17 peter 393
3948 20 Jul 20 peter 394       typedef std::list<boost::shared_ptr<std::thread> > WorkerList;
3918 31 May 20 peter 395       // We keep workers here (rather than in JobHandler::operator()
3918 31 May 20 peter 396       // scope), so we can access it from other functions and don't
3918 31 May 20 peter 397       // need to pass it around.
3848 23 Sep 19 peter 398       WorkerList workers_;
3848 23 Sep 19 peter 399       // Number of Workers minus number of poison pills sent for them
3848 23 Sep 19 peter 400       unsigned int n_target_workers_;
3848 23 Sep 19 peter 401     }; // end class JobHandler
3681 22 Aug 17 peter 402
3681 22 Aug 17 peter 403     // If an error has been detected (and stored in error_), rethrow it.
3694 23 Sep 17 peter 404     void throw_if_error(void) const;
3346 06 Nov 14 peter 405
3948 20 Jul 20 peter 406     mutable std::mutex mutex_;
3823 16 Jul 19 peter 407     JobHandlerData data_;
3948 20 Jul 20 peter 408     std::thread job_handler_;
3346 06 Nov 14 peter 409   }; // end class Scheduler
3346 06 Nov 14 peter 410
3346 06 Nov 14 peter 411 }}}
3346 06 Nov 14 peter 412 #endif