Panda3D
asyncTaskChain.h
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file asyncTaskChain.h
10  * @author drose
11  * @date 2006-08-23
12  */
13 
14 #ifndef ASYNCTASKCHAIN_H
15 #define ASYNCTASKCHAIN_H
16 
17 #include "pandabase.h"
18 
19 #include "asyncTask.h"
20 #include "asyncTaskCollection.h"
21 #include "typedReferenceCount.h"
22 #include "thread.h"
23 #include "conditionVarFull.h"
24 #include "pvector.h"
25 #include "pdeque.h"
26 #include "pStatCollector.h"
27 #include "clockObject.h"
28 
29 class AsyncTaskManager;
30 
31 /**
32  * The AsyncTaskChain is a subset of the AsyncTaskManager. Each chain
33  * maintains a separate list of tasks, and will execute them with its own set
34  * of threads. Each chain may thereby operate independently of the other
35  * chains.
36  *
37  * The AsyncTaskChain will spawn a specified number of threads (possibly 0) to
38  * serve the tasks. If there are no threads, you must call poll() from time
39  * to time to serve the tasks in the main thread. Normally this is done by
40  * calling AsyncTaskManager::poll().
41  *
42  * Each task will run exactly once each epoch. Beyond that, the tasks' sort
43  * and priority values control the order in which they are run: tasks are run
44  * in increasing order by sort value, and within the same sort value, they are
45  * run roughly in decreasing order by priority value, with some exceptions for
46  * parallelism. Tasks with different sort values are never run in parallel
47  * together, but tasks with different priority values might be (if there is
48  * more than one thread).
49  */
50 class EXPCL_PANDA_EVENT AsyncTaskChain : public TypedReferenceCount, public Namable {
51 public:
52  AsyncTaskChain(AsyncTaskManager *manager, const std::string &name);
53  ~AsyncTaskChain();
54 
55 PUBLISHED:
56  void set_tick_clock(bool tick_clock);
57  bool get_tick_clock() const;
58 
59  BLOCKING void set_num_threads(int num_threads);
60  int get_num_threads() const;
61  int get_num_running_threads() const;
62 
63  BLOCKING void set_thread_priority(ThreadPriority priority);
64  ThreadPriority get_thread_priority() const;
65 
66  void set_frame_budget(double frame_budget);
67  double get_frame_budget() const;
68 
69  void set_frame_sync(bool frame_sync);
70  bool get_frame_sync() const;
71 
72  void set_timeslice_priority(bool timeslice_priority);
73  bool get_timeslice_priority() const;
74 
75  BLOCKING void stop_threads();
76  void start_threads();
77  INLINE bool is_started() const;
78 
79  bool has_task(AsyncTask *task) const;
80 
81  BLOCKING void wait_for_tasks();
82 
83  int get_num_tasks() const;
84  AsyncTaskCollection get_tasks() const;
85  AsyncTaskCollection get_active_tasks() const;
86  AsyncTaskCollection get_sleeping_tasks() const;
87 
88  void poll();
89  double get_next_wake_time() const;
90 
91  virtual void output(std::ostream &out) const;
92  virtual void write(std::ostream &out, int indent_level = 0) const;
93 
94 protected:
95  class AsyncTaskChainThread;
96  typedef pvector< PT(AsyncTask) > TaskHeap;
97 
98  void do_add(AsyncTask *task);
99  bool do_remove(AsyncTask *task, bool upon_death=false);
100  void do_wait_for_tasks();
101  void do_cleanup();
102 
103  bool do_has_task(AsyncTask *task) const;
104  int find_task_on_heap(const TaskHeap &heap, AsyncTask *task) const;
105 
106  void service_one_task(AsyncTaskChainThread *thread);
107  void cleanup_task(AsyncTask *task, bool upon_death, bool clean_exit);
108  bool finish_sort_group();
109  void filter_timeslice_priority();
110  void do_stop_threads();
111  void do_start_threads();
112  AsyncTaskCollection do_get_active_tasks() const;
113  AsyncTaskCollection do_get_sleeping_tasks() const;
114  void do_poll();
115  void cleanup_pickup_mode();
116  INLINE double do_get_next_wake_time() const;
117  static INLINE double get_wake_time(AsyncTask *task);
118  void do_output(std::ostream &out) const;
119  void do_write(std::ostream &out, int indent_level) const;
120 
121  void write_task_line(std::ostream &out, int indent_level, AsyncTask *task, double now) const;
122 
123 protected:
124  class AsyncTaskChainThread : public Thread {
125  public:
126  AsyncTaskChainThread(const std::string &name, AsyncTaskChain *chain);
127  virtual void thread_main();
128 
129  AsyncTaskChain *_chain;
130  AsyncTask *_servicing;
131  };
132 
133  class AsyncTaskSortWakeTime {
134  public:
135  bool operator () (AsyncTask *a, AsyncTask *b) const {
136  return AsyncTaskChain::get_wake_time(a) > AsyncTaskChain::get_wake_time(b);
137  }
138  };
139 
140  class AsyncTaskSortPriority {
141  public:
142  bool operator () (AsyncTask *a, AsyncTask *b) const {
143  if (a->get_sort() != b->get_sort()) {
144  return a->get_sort() > b->get_sort();
145  }
146  if (a->get_priority() != b->get_priority()) {
147  return a->get_priority() < b->get_priority();
148  }
149  if (a->get_start_time() != b->get_start_time()) {
150  return a->get_start_time() > b->get_start_time();
151  }
152  // Failing any other ordering criteria, we sort the tasks based on the
153  // order in which they were added to the task chain.
154  return a->_implicit_sort > b->_implicit_sort;
155  }
156  };
157 
158  typedef pvector< PT(AsyncTaskChainThread) > Threads;
159 
160  AsyncTaskManager *_manager;
161 
162  ConditionVarFull _cvar; // signaled when one of the task heaps, _state, or _current_sort changes, or a task finishes.
163 
164  enum State {
165  S_initial, // no threads yet
166  S_started, // threads have been started
167  S_interrupted, // task returned DS_interrupt, requested from sub-thread.
168  S_shutdown // waiting for thread shutdown, requested from main thread
169  };
170 
171  bool _tick_clock;
172  bool _timeslice_priority;
173  int _num_threads;
174  ThreadPriority _thread_priority;
175  Threads _threads;
176  double _frame_budget;
177  bool _frame_sync;
178  int _num_busy_threads;
179  int _num_tasks;
180  int _num_awaiting_tasks;
181  TaskHeap _active;
182  TaskHeap _this_active;
183  TaskHeap _next_active;
184  TaskHeap _sleeping;
185  State _state;
186  int _current_sort;
187  bool _pickup_mode;
188  bool _needs_cleanup;
189 
190  int _current_frame;
191  double _time_in_frame;
192  bool _block_till_next_frame;
193 
194  unsigned int _next_implicit_sort;
195 
196  static PStatCollector _task_pcollector;
197  static PStatCollector _wait_pcollector;
198 
199 public:
200  static TypeHandle get_class_type() {
201  return _type_handle;
202  }
203  static void init_type() {
204  TypedReferenceCount::init_type();
205  register_type(_type_handle, "AsyncTaskChain",
206  TypedReferenceCount::get_class_type());
207  }
208  virtual TypeHandle get_type() const {
209  return get_class_type();
210  }
211  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
212 
213 private:
214  static TypeHandle _type_handle;
215 
216  friend class AsyncFuture;
217  friend class AsyncTaskChainThread;
218  friend class AsyncTask;
219  friend class AsyncTaskManager;
220  friend class AsyncTaskSortWakeTime;
221 };
222 
223 INLINE std::ostream &operator << (std::ostream &out, const AsyncTaskChain &chain) {
224  chain.output(out);
225  return out;
226 };
227 
228 #include "asyncTaskChain.I"
229 
230 #endif
This class represents a thread-safe handle to a promised future result of an asynchronous operation,...
Definition: asyncFuture.h:61
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A class to manage a loose queue of isolated tasks, which can be performed either synchronously (in th...
void register_type(TypeHandle &type_handle, const std::string &name)
This inline function is just a convenient way to call TypeRegistry::register_type(),...
Definition: register_type.I:22
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A list of tasks, for instance as returned by some of the AsyncTaskManager query functions.
get_sort
Returns the task's current sort value.
Definition: asyncTask.h:115
A base class for things which need to inherit from both TypedObject and from ReferenceCount.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
void output(std::ostream &out) const
Outputs the Namable.
Definition: namable.I:61
A lightweight class that represents a single element that may be timed and/or counted via stats.
A base class for all things which can have a name.
Definition: namable.h:26
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The AsyncTaskChain is a subset of the AsyncTaskManager.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
double get_start_time() const
Returns the time at which the task was started, according to the task manager's clock.
Definition: asyncTask.I:112
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class represents a concrete task performed by an AsyncManager.
Definition: asyncTask.h:32
This class implements a condition variable; see ConditionVar for a brief introduction to this class.
A thread; that is, a lightweight process.
Definition: thread.h:46
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_priority
Returns the task's current priority value.
Definition: asyncTask.h:116