source: trunk/yat/utility/Scheduler.h @ 3346

Last change on this file since 3346 was 3346, checked in by Peter, 8 years ago

first version of Scheduler class. refs #800.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 4.9 KB
Line 
1#ifndef theplu_yat_utility_scheduler
2#define theplu_yat_utility_scheduler
3
4// $Id: Scheduler.h 3346 2014-11-06 13:16:34Z peter $
5
6/*
7  Copyright (C) 2014 Peter Johansson
8
9  This file is part of the yat library, http://dev.thep.lu.se/yat
10
11  The yat library is free software; you can redistribute it and/or
12  modify it under the terms of the GNU General Public License as
13  published by the Free Software Foundation; either version 3 of the
14  License, or (at your option) any later version.
15
16  The yat library is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  General Public License for more details.
20
21  You should have received a copy of the GNU General Public License
22  along with yat. If not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include "Queue.h"
26
27#include <boost/thread.hpp>
28#include <boost/shared_ptr.hpp>
29
30#include <set>
31#include <deque>
32
33namespace theplu {
34namespace yat {
35namespace utility {
36
37  /**
38     \brief Handle a number of jobs and send them to threads
39
40     Scheduler starts a (user defined) number of threads and handles a
41     series of Jobs. The Jobs can have dependencies, such that Job X
42     must finish before Job Y can run, and the Scheduler takes care of
43     these dependencies. It possible to create new Jobs within a Job
44     (see Job::submit) and these will be processed when the current
45     Job has completed. Here is a small code example in which two
46     threads are used to process the four jobs, \c MyJob. The jobs
47     have a dependency that job4 can not run until the three first
48     jobs have completed.
49
50     \code
51
52     Scheduler scheduler(2);
53     boost::shared_ptr<MyJob> job1(new MyJob("Hello"));
54     boost::shared_ptr<MyJob> job1(new MyJob(" "));
55     boost::shared_ptr<MyJob> job3(new MyJob("World"));
56     boost::shared_ptr<MyJob> job4(new MyJob("\n"));
57     job4.add_dependency(job1);
58     job4.add_dependency(job2);
59     job4.add_dependency(job3);
60     scheduler.submit(job4);
61     scheduler.launch();
62
63     \endcode
64   */
65  class Scheduler
66  {
67  public:
68    /**
69       Base class that defines the interface for a Job
70     */
71    class Job
72    {
73    public:
74      /**
75         \brief constructor
76       */
77      Job(void);
78
79      /**
80         \brief destructor
81       */
82      virtual ~Job(void);
83
84      /**
85         \brief add a dependency
86
87         This job will not be processed until \a job has finished.
88       */
89      void add_dependency(boost::shared_ptr<Job> job);
90
91      /**
92         This function defines the work done in thread.
93       */
94      virtual void operator()(void)=0;
95    protected:
96      /**
97         \brief Add a Job
98
99         Typically called within operator(). When this Job has
100         completed, the Scheduler will collect jobs passed to submit
101         and send them to the queue just like if they had been passed
102         to Scheduler::submit.
103       */
104      void submit(boost::shared_ptr<Job> job);
105    private:
106      friend class Scheduler;
107      // set of jobs that have to finish before this can run
108      std::set<boost::shared_ptr<Job> > parents_;
109      // jobs created within this job
110      std::vector<boost::shared_ptr<Job> > sub_jobs_;
111      enum status { pristine, prepared, running, completed};
112      status status_;
113    }; // end class Job
114
115    /**
116       \brief constructor
117
118       \param threads number of threads that are used
119     */
120    Scheduler(unsigned int threads);
121
122    /**
123       Launch submitted jobs to threads and wait until all jobs have finished.
124     */
125    void launch(void);
126
127    /**
128       Add \a job to list of jobs that should be processed in launch(void)
129     */
130    void submit(boost::shared_ptr<Job> job);
131
132  private:
133    // \internal class that does the job
134    //
135    // It processes any job that is pushed to the \a queue until a
136    // NULL Job shows up which signals that the work is done. When
137    // NULL is observed the NULL Job is pushed to the queue so
138    // co-workers are notified too.
139    class Worker
140    {
141    public:
142      Worker(Queue<boost::shared_ptr<Job> >& queue,
143             Queue<boost::shared_ptr<Job> >& completed);
144      void operator()(void);
145    private:
146      Queue<boost::shared_ptr<Job> >& queue_;
147      Queue<boost::shared_ptr<Job> >& completed_;
148    }; // end class Worker
149
150    // function called when job has finished and returned from
151    // worker. If there are any jobs that depends on \a job those jobs
152    // are notified and if it makes them ready to be processed they
153    // are sent to queue.
154    void post_process(boost::shared_ptr<Job> job);
155
156    // If \a job has parent jobs, which need to finish first, update
157    // map children_ to reflect that. If all parents have finished,
158    // send job to queue.
159    void process(boost::shared_ptr<Job> job);
160
161    // send job to queue
162    void queue(boost::shared_ptr<Job> job);
163
164    typedef boost::shared_ptr<Scheduler::Job> JobPtr;
165    std::deque<JobPtr> jobs_;
166    std::set<JobPtr> running_jobs_;
167
168    // value lists all jobs that depend on key, i.e., key has to
169    // finish before jobs in value can start
170    std::map<JobPtr, std::vector<JobPtr> > children_;
171
172    Queue<boost::shared_ptr<Job> > queue_;
173    Queue<boost::shared_ptr<Job> > completed_;
174    boost::thread_group workers_;
175
176  }; // end class Scheduler
177
178}}}
179#endif
Note: See TracBrowser for help on using the repository browser.