Panda3D
asyncTaskManager.cxx
1 // Filename: asyncTaskManager.cxx
2 // Created by: drose (23Aug06)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "asyncTaskManager.h"
16 #include "event.h"
17 #include "pt_Event.h"
18 #include "mutexHolder.h"
19 #include "indent.h"
20 #include "pStatClient.h"
21 #include "pStatTimer.h"
22 #include "clockObject.h"
23 #include "config_event.h"
24 #include <algorithm>
25 
26 AsyncTaskManager *AsyncTaskManager::_global_ptr = NULL;
27 
28 TypeHandle AsyncTaskManager::_type_handle;
29 
30 ////////////////////////////////////////////////////////////////////
31 // Function: AsyncTaskManager::Constructor
32 // Access: Published
33 // Description:
34 ////////////////////////////////////////////////////////////////////
35 AsyncTaskManager::
36 AsyncTaskManager(const string &name) :
37  Namable(name),
38  _lock("AsyncTaskManager::_lock"),
39  _num_tasks(0),
40  _clock(ClockObject::get_global_clock()),
41  _frame_cvar(_lock)
42 {
43  // Make a default task chain.
44  do_make_task_chain("default");
45 }
46 
47 ////////////////////////////////////////////////////////////////////
48 // Function: AsyncTaskManager::Destructor
49 // Access: Published, Virtual
50 // Description:
51 ////////////////////////////////////////////////////////////////////
52 AsyncTaskManager::
53 ~AsyncTaskManager() {
54  cleanup();
55 }
56 
57 ////////////////////////////////////////////////////////////////////
58 // Function: AsyncTaskManager::cleanup
59 // Access: Published
60 // Description: Stops all threads and messily empties the task list.
61 // This is intended to be called on destruction only.
62 ////////////////////////////////////////////////////////////////////
65  MutexHolder holder(_lock);
66 
67  if (task_cat.is_debug()) {
68  do_output(task_cat.debug());
69  task_cat.debug(false)
70  << ": cleanup()\n";
71  }
72 
73  // Iterate carefully in case the tasks adjust the chain list within
74  // cleanup().
75  while (!_task_chains.empty()) {
76  PT(AsyncTaskChain) chain = _task_chains[_task_chains.size() - 1];
77  _task_chains.pop_back();
78  chain->do_cleanup();
79  }
80 
81  // There might be one remaining task, the current task. Especially
82  // if it wasn't running on a thread.
83  if (_num_tasks == 1) {
84  nassertv(_tasks_by_name.size() == 1);
85  TasksByName::const_iterator tbni = _tasks_by_name.begin();
86  AsyncTask *task = (*tbni);
87  nassertv(task->_state == AsyncTask::S_servicing ||
88  task->_state == AsyncTask::S_servicing_removed);
89  task->_state = AsyncTask::S_servicing_removed;
90 
91  } else {
92  // If there isn't exactly one remaining task, there should be
93  // none.
94 #ifndef NDEBUG
95  nassertd(_num_tasks == 0 && _tasks_by_name.empty()) {
96  task_cat.error()
97  << "_num_tasks = " << _num_tasks << " _tasks_by_name = " << _tasks_by_name.size() << "\n";
98  TasksByName::const_iterator tbni;
99  for (tbni = _tasks_by_name.begin();
100  tbni != _tasks_by_name.end();
101  ++tbni) {
102  task_cat.error()
103  << " " << *(*tbni) << "\n";
104  }
105  }
106 #endif // NDEBUG
107  }
108 }
109 
110 ////////////////////////////////////////////////////////////////////
111 // Function: AsyncTaskManager::get_num_task_chains
112 // Access: Published
113 // Description: Returns the number of different task chains.
114 ////////////////////////////////////////////////////////////////////
117  MutexHolder holder(_lock);
118  return _task_chains.size();
119 }
120 
121 ////////////////////////////////////////////////////////////////////
122 // Function: AsyncTaskManager::get_task_chain
123 // Access: Published
124 // Description: Returns the nth task chain.
125 ////////////////////////////////////////////////////////////////////
127 get_task_chain(int n) const {
128  MutexHolder holder(_lock);
129  nassertr(n >= 0 && n < (int)_task_chains.size(), NULL);
130  return _task_chains[n];
131 }
132 
133 ////////////////////////////////////////////////////////////////////
134 // Function: AsyncTaskManager::make_task_chain
135 // Access: Published
136 // Description: Creates a new AsyncTaskChain of the indicated name
137 // and stores it within the AsyncTaskManager. If a task
138 // chain with this name already exists, returns it
139 // instead.
140 ////////////////////////////////////////////////////////////////////
142 make_task_chain(const string &name) {
143  MutexHolder holder(_lock);
144  return do_make_task_chain(name);
145 }
146 
147 ////////////////////////////////////////////////////////////////////
148 // Function: AsyncTaskManager::find_task_chain
149 // Access: Protected
150 // Description: Searches a new AsyncTaskChain of the indicated name
151 // and returns it if it exists, or NULL otherwise.
152 ////////////////////////////////////////////////////////////////////
154 find_task_chain(const string &name) {
155  MutexHolder holder(_lock);
156  return do_find_task_chain(name);
157 }
158 
159 ////////////////////////////////////////////////////////////////////
160 // Function: AsyncTaskManager::remove_task_chain
161 // Access: Protected
162 // Description: Removes the AsyncTaskChain of the indicated name.
163 // If the chain still has tasks, this will block until
164 // all tasks are finished.
165 //
166 // Returns true if successful, or false if the chain did
167 // not exist.
168 ////////////////////////////////////////////////////////////////////
170 remove_task_chain(const string &name) {
171  MutexHolder holder(_lock);
172 
173  PT(AsyncTaskChain) chain = new AsyncTaskChain(this, name);
174  TaskChains::iterator tci = _task_chains.find(chain);
175  if (tci == _task_chains.end()) {
176  // No chain.
177  return false;
178  }
179 
180  chain = (*tci);
181 
182  while (chain->_num_tasks != 0) {
183  // Still has tasks.
184  task_cat.info()
185  << "Waiting for tasks on chain " << name << " to finish.\n";
186  chain->do_wait_for_tasks();
187  }
188 
189  // Safe to remove.
190  chain->do_cleanup();
191  _task_chains.erase(tci);
192  return true;
193 }
194 
195 ////////////////////////////////////////////////////////////////////
196 // Function: AsyncTaskManager::add
197 // Access: Published
198 // Description: Adds the indicated task to the active queue. It is
199 // an error if the task is already added to this or any
200 // other active queue.
201 ////////////////////////////////////////////////////////////////////
203 add(AsyncTask *task) {
204  nassertv(task->is_runnable());
205 
206  {
207  MutexHolder holder(_lock);
208 
209  if (task_cat.is_debug()) {
210  task_cat.debug()
211  << "Adding " << *task << "\n";
212  }
213 
214  if (task->_state == AsyncTask::S_servicing_removed) {
215  if (task->_manager == this) {
216  // Re-adding a self-removed task; this just means clearing the
217  // removed flag.
218  task->_state = AsyncTask::S_servicing;
219  return;
220  }
221  }
222 
223  nassertv(task->_manager == NULL &&
224  task->_state == AsyncTask::S_inactive);
225  nassertv(!do_has_task(task));
226 
227  _lock.release();
228  task->upon_birth(this);
229  _lock.acquire();
230  nassertv(task->_manager == NULL &&
231  task->_state == AsyncTask::S_inactive);
232  nassertv(!do_has_task(task));
233 
234  AsyncTaskChain *chain = do_find_task_chain(task->_chain_name);
235  if (chain == (AsyncTaskChain *)NULL) {
236  task_cat.warning()
237  << "Creating implicit AsyncTaskChain " << task->_chain_name
238  << " for " << get_type() << " " << get_name() << "\n";
239  chain = do_make_task_chain(task->_chain_name);
240  }
241  chain->do_add(task);
242  }
243 }
244 
245 ////////////////////////////////////////////////////////////////////
246 // Function: AsyncTaskManager::has_task
247 // Access: Published
248 // Description: Returns true if the indicated task has been added to
249 // this AsyncTaskManager, false otherwise.
250 ////////////////////////////////////////////////////////////////////
252 has_task(AsyncTask *task) const {
253  MutexHolder holder(_lock);
254 
255  if (task->_manager != this) {
256  nassertr(!do_has_task(task), false);
257  return false;
258  }
259 
260  if (task->_state == AsyncTask::S_servicing_removed) {
261  return false;
262  }
263 
264  // The task might not actually be in the active queue, since it
265  // might be being serviced right now. That's OK.
266  return true;
267 }
268 
269 ////////////////////////////////////////////////////////////////////
270 // Function: AsyncTaskManager::find_task
271 // Access: Published
272 // Description: Returns the first task found with the indicated name,
273 // or NULL if there is no task with the indicated name.
274 //
275 // If there are multiple tasks with the same name,
276 // returns one of them arbitrarily.
277 ////////////////////////////////////////////////////////////////////
279 find_task(const string &name) const {
280  AsyncTask sample_task(name);
281  sample_task.local_object();
282 
283  TasksByName::const_iterator tbni = _tasks_by_name.lower_bound(&sample_task);
284  if (tbni != _tasks_by_name.end() && (*tbni)->get_name() == name) {
285  return (*tbni);
286  }
287 
288  return NULL;
289 }
290 
291 ////////////////////////////////////////////////////////////////////
292 // Function: AsyncTaskManager::find_tasks
293 // Access: Published
294 // Description: Returns the list of tasks found with the indicated
295 // name.
296 ////////////////////////////////////////////////////////////////////
298 find_tasks(const string &name) const {
299  AsyncTask sample_task(name);
300  sample_task.local_object();
301 
302  TasksByName::const_iterator tbni = _tasks_by_name.lower_bound(&sample_task);
303  AsyncTaskCollection result;
304  while (tbni != _tasks_by_name.end() && (*tbni)->get_name() == name) {
305  result.add_task(*tbni);
306  ++tbni;
307  }
308 
309  return result;
310 }
311 
312 ////////////////////////////////////////////////////////////////////
313 // Function: AsyncTaskManager::find_tasks_matching
314 // Access: Published
315 // Description: Returns the list of tasks found whose name matches
316 // the indicated glob pattern, e.g. "my_task_*".
317 ////////////////////////////////////////////////////////////////////
319 find_tasks_matching(const GlobPattern &pattern) const {
320  string prefix = pattern.get_const_prefix();
321  AsyncTask sample_task(prefix);
322  sample_task.local_object();
323 
324  TasksByName::const_iterator tbni = _tasks_by_name.lower_bound(&sample_task);
325  AsyncTaskCollection result;
326  while (tbni != _tasks_by_name.end() && (*tbni)->get_name().substr(0, prefix.size()) == prefix) {
327  AsyncTask *task = (*tbni);
328  if (pattern.matches(task->get_name())) {
329  result.add_task(task);
330  }
331  ++tbni;
332  }
333 
334  return result;
335 }
336 
337 ////////////////////////////////////////////////////////////////////
338 // Function: AsyncTaskManager::remove
339 // Access: Published
340 // Description: Removes the indicated task from the active queue.
341 // Returns true if the task is successfully removed, or
342 // false if it wasn't there.
343 ////////////////////////////////////////////////////////////////////
346  // We pass this up to the multi-task remove() flavor. Do we care
347  // about the tiny cost of creating an AsyncTaskCollection here?
348  // Probably not.
349  AsyncTaskCollection tasks;
350  tasks.add_task(task);
351  return remove(tasks) != 0;
352 }
353 
354 ////////////////////////////////////////////////////////////////////
355 // Function: AsyncTaskManager::remove
356 // Access: Published
357 // Description: Removes all of the tasks in the AsyncTaskCollection.
358 // Returns the number of tasks removed.
359 ////////////////////////////////////////////////////////////////////
362  MutexHolder holder(_lock);
363  int num_removed = 0;
364 
365  int num_tasks = tasks.get_num_tasks();
366  int i;
367  for (i = 0; i < num_tasks; ++i) {
368  PT(AsyncTask) task = tasks.get_task(i);
369 
370  if (task->_manager != this) {
371  // Not a member of this manager, or already removed.
372  nassertr(!do_has_task(task), num_removed);
373  } else {
374  nassertr(task->_chain->_manager == this, num_removed);
375  if (task_cat.is_debug()) {
376  task_cat.debug()
377  << "Removing " << *task << "\n";
378  }
379  if (task->_chain->do_remove(task)) {
380  _lock.release();
381  task->upon_death(this, false);
382  _lock.acquire();
383  ++num_removed;
384  } else {
385  if (task_cat.is_debug()) {
386  task_cat.debug()
387  << " (unable to remove " << *task << ")\n";
388  }
389  }
390  }
391  }
392 
393  return num_removed;
394 }
395 
396 ////////////////////////////////////////////////////////////////////
397 // Function: AsyncTaskManager::wait_for_tasks
398 // Access: Published
399 // Description: Blocks until the task list is empty.
400 ////////////////////////////////////////////////////////////////////
403  MutexHolder holder(_lock);
404 
405  // Wait for each of our task chains to finish.
406  while (_num_tasks > 0) {
407  // We iterate through with an index, rather than with an iterator,
408  // because it's possible for a task to adjust the task_chain list
409  // during its execution.
410  for (unsigned int i = 0; i < _task_chains.size(); ++i) {
411  AsyncTaskChain *chain = _task_chains[i];
412  chain->do_wait_for_tasks();
413  }
414  }
415 }
416 
417 ////////////////////////////////////////////////////////////////////
418 // Function: AsyncTaskManager::stop_threads
419 // Access: Published
420 // Description: Stops any threads that are currently running. If any
421 // tasks are still pending and have not yet been picked
422 // up by a thread, they will not be serviced unless
423 // poll() or start_threads() is later called.
424 ////////////////////////////////////////////////////////////////////
427  MutexHolder holder(_lock);
428 
429  // We iterate through with an index, rather than with an iterator,
430  // because it's possible for a task to adjust the task_chain list
431  // during its execution.
432  for (unsigned int i = 0; i < _task_chains.size(); ++i) {
433  AsyncTaskChain *chain = _task_chains[i];
434  chain->do_stop_threads();
435  }
436 }
437 
438 ////////////////////////////////////////////////////////////////////
439 // Function: AsyncTaskManager::start_threads
440 // Access: Published
441 // Description: Starts any requested threads to service the tasks on
442 // the queue. This is normally not necessary, since
443 // adding a task will start the threads automatically.
444 ////////////////////////////////////////////////////////////////////
447  MutexHolder holder(_lock);
448 
449  // We iterate through with an index, rather than with an iterator,
450  // because it's possible for a task to adjust the task_chain list
451  // during its execution.
452  for (unsigned int i = 0; i < _task_chains.size(); ++i) {
453  AsyncTaskChain *chain = _task_chains[i];
454 
455  chain->do_start_threads();
456  }
457 }
458 
459 ////////////////////////////////////////////////////////////////////
460 // Function: AsyncTaskManager::get_tasks
461 // Access: Published
462 // Description: Returns the set of tasks that are active or sleeping
463 // on the task manager, at the time of the call.
464 ////////////////////////////////////////////////////////////////////
466 get_tasks() const {
467  MutexHolder holder(_lock);
468 
469  AsyncTaskCollection result;
470  TaskChains::const_iterator tci;
471  for (tci = _task_chains.begin();
472  tci != _task_chains.end();
473  ++tci) {
474  AsyncTaskChain *chain = (*tci);
475  result.add_tasks_from(chain->do_get_active_tasks());
476  result.add_tasks_from(chain->do_get_sleeping_tasks());
477  }
478 
479  return result;
480 }
481 
482 ////////////////////////////////////////////////////////////////////
483 // Function: AsyncTaskManager::get_active_tasks
484 // Access: Published
485 // Description: Returns the set of tasks that are active (and not
486 // sleeping) on the task manager, at the time of the
487 // call.
488 ////////////////////////////////////////////////////////////////////
491  MutexHolder holder(_lock);
492 
493  AsyncTaskCollection result;
494  TaskChains::const_iterator tci;
495  for (tci = _task_chains.begin();
496  tci != _task_chains.end();
497  ++tci) {
498  AsyncTaskChain *chain = (*tci);
499  result.add_tasks_from(chain->do_get_active_tasks());
500  }
501 
502  return result;
503 }
504 
505 ////////////////////////////////////////////////////////////////////
506 // Function: AsyncTaskManager::get_sleeping_tasks
507 // Access: Published
508 // Description: Returns the set of tasks that are sleeping (and not
509 // active) on the task manager, at the time of the
510 // call.
511 ////////////////////////////////////////////////////////////////////
514  MutexHolder holder(_lock);
515 
516  AsyncTaskCollection result;
517  TaskChains::const_iterator tci;
518  for (tci = _task_chains.begin();
519  tci != _task_chains.end();
520  ++tci) {
521  AsyncTaskChain *chain = (*tci);
522  result.add_tasks_from(chain->do_get_sleeping_tasks());
523  }
524 
525  return result;
526 }
527 
528 ////////////////////////////////////////////////////////////////////
529 // Function: AsyncTaskManager::poll
530 // Access: Published
531 // Description: Runs through all the tasks in the task list, once, if
532 // the task manager is running in single-threaded mode
533 // (no threads available). This method does nothing in
534 // threaded mode, so it may safely be called in either
535 // case.
536 ////////////////////////////////////////////////////////////////////
538 poll() {
539  MutexHolder holder(_lock);
540 
541  // We iterate through with an index, rather than with an iterator,
542  // because it's possible for a task to adjust the task_chain list
543  // during its execution.
544  for (unsigned int i = 0; i < _task_chains.size(); ++i) {
545  AsyncTaskChain *chain = _task_chains[i];
546  chain->do_poll();
547  }
548 
549  // Just in case the clock was ticked explicitly by one of our
550  // polling chains.
551  _frame_cvar.notify_all();
552 }
553 
554 ////////////////////////////////////////////////////////////////////
555 // Function: AsyncTaskManager::get_next_wake_time
556 // Access: Published
557 // Description: Returns the scheduled time (on the manager's clock)
558 // of the next sleeping task, on any task chain, to
559 // awaken. Returns -1 if there are no sleeping tasks.
560 ////////////////////////////////////////////////////////////////////
561 double AsyncTaskManager::
563  MutexHolder holder(_lock);
564 
565  bool got_any = false;
566  double next_wake_time = -1.0;
567 
568  TaskChains::const_iterator tci;
569  for (tci = _task_chains.begin();
570  tci != _task_chains.end();
571  ++tci) {
572  AsyncTaskChain *chain = (*tci);
573  double time = chain->do_get_next_wake_time();
574  if (time >= 0.0) {
575  if (!got_any) {
576  got_any = true;
577  next_wake_time = time;
578  } else {
579  next_wake_time = min(time, next_wake_time);
580  }
581  }
582  }
583 
584  return next_wake_time;
585 }
586 
587 ////////////////////////////////////////////////////////////////////
588 // Function: AsyncTaskManager::output
589 // Access: Published, Virtual
590 // Description:
591 ////////////////////////////////////////////////////////////////////
592 void AsyncTaskManager::
593 output(ostream &out) const {
594  MutexHolder holder(_lock);
595  do_output(out);
596 }
597 
598 ////////////////////////////////////////////////////////////////////
599 // Function: AsyncTaskManager::write
600 // Access: Published, Virtual
601 // Description:
602 ////////////////////////////////////////////////////////////////////
603 void AsyncTaskManager::
604 write(ostream &out, int indent_level) const {
605  MutexHolder holder(_lock);
606  indent(out, indent_level)
607  << get_type() << " " << get_name() << "\n";
608 
609  TaskChains::const_iterator tci;
610  for (tci = _task_chains.begin();
611  tci != _task_chains.end();
612  ++tci) {
613  AsyncTaskChain *chain = (*tci);
614  if (chain->_num_tasks != 0) {
615  out << "\n";
616  chain->do_write(out, indent_level + 2);
617  }
618  }
619 }
620 
621 ////////////////////////////////////////////////////////////////////
622 // Function: AsyncTaskManager::do_make_task_chain
623 // Access: Protected
624 // Description: Creates a new AsyncTaskChain of the indicated name
625 // and stores it within the AsyncTaskManager. If a task
626 // chain with this name already exists, returns it
627 // instead.
628 //
629 // Assumes the lock is held.
630 ////////////////////////////////////////////////////////////////////
631 AsyncTaskChain *AsyncTaskManager::
632 do_make_task_chain(const string &name) {
633  PT(AsyncTaskChain) chain = new AsyncTaskChain(this, name);
634 
635  TaskChains::const_iterator tci = _task_chains.insert(chain).first;
636  return (*tci);
637 }
638 
639 ////////////////////////////////////////////////////////////////////
640 // Function: AsyncTaskManager::do_find_task_chain
641 // Access: Protected
642 // Description: Searches a new AsyncTaskChain of the indicated name
643 // and returns it if it exists, or NULL otherwise.
644 //
645 // Assumes the lock is held.
646 ////////////////////////////////////////////////////////////////////
647 AsyncTaskChain *AsyncTaskManager::
648 do_find_task_chain(const string &name) {
649  PT(AsyncTaskChain) chain = new AsyncTaskChain(this, name);
650 
651  TaskChains::const_iterator tci = _task_chains.find(chain);
652  if (tci != _task_chains.end()) {
653  return (*tci);
654  }
655 
656  return NULL;
657 }
658 
659 ////////////////////////////////////////////////////////////////////
660 // Function: AsyncTaskManager::remove_task_by_name
661 // Access: Protected
662 // Description: Removes the task from the _tasks_by_name index, if it
663 // has a nonempty name.
664 ////////////////////////////////////////////////////////////////////
665 void AsyncTaskManager::
666 remove_task_by_name(AsyncTask *task) {
667  if (!task->get_name().empty()) {
668  // We have to scan linearly through all of the tasks with the same
669  // name.
670  TasksByName::iterator tbni = _tasks_by_name.lower_bound(task);
671  while (tbni != _tasks_by_name.end()) {
672  if ((*tbni) == task) {
673  _tasks_by_name.erase(tbni);
674  return;
675  }
676  if ((*tbni)->get_name() != task->get_name()) {
677  // Too far.
678  break;
679  }
680 
681  ++tbni;
682  }
683 
684  // For some reason, the task wasn't on the index.
685  nassertv(false);
686  }
687 }
688 
689 ////////////////////////////////////////////////////////////////////
690 // Function: AsyncTaskManager::do_has_task
691 // Access: Protected
692 // Description: Returns true if the task is on one of the task lists,
693 // false if it is not (false may mean that the task is
694 // currently being serviced). Assumes the lock is
695 // currently held.
696 ////////////////////////////////////////////////////////////////////
697 bool AsyncTaskManager::
698 do_has_task(AsyncTask *task) const {
699  TaskChains::const_iterator tci;
700  for (tci = _task_chains.begin();
701  tci != _task_chains.end();
702  ++tci) {
703  AsyncTaskChain *chain = (*tci);
704  if (chain->do_has_task(task)) {
705  return true;
706  }
707  }
708 
709  return false;
710 }
711 
712 ////////////////////////////////////////////////////////////////////
713 // Function: AsyncTaskManager::do_output
714 // Access: Protected, Virtual
715 // Description:
716 ////////////////////////////////////////////////////////////////////
717 void AsyncTaskManager::
718 do_output(ostream &out) const {
719  out << get_type() << " " << get_name()
720  << "; " << _num_tasks << " tasks";
721 }
722 
723 ////////////////////////////////////////////////////////////////////
724 // Function: AsyncTaskManager::make_global_ptr
725 // Access: Private, Static
726 // Description: Called once per application to create the global
727 // task manager object.
728 ////////////////////////////////////////////////////////////////////
729 void AsyncTaskManager::
730 make_global_ptr() {
731  nassertv(_global_ptr == (AsyncTaskManager *)NULL);
732 
733  _global_ptr = new AsyncTaskManager("TaskManager");
734  _global_ptr->ref();
735 }
bool matches(const string &candidate) const
Returns true if the candidate string matches the pattern, false otherwise.
Definition: globPattern.I:157
AsyncTaskChain * make_task_chain(const string &name)
Creates a new AsyncTaskChain of the indicated name and stores it within the AsyncTaskManager.
void pop_back()
Removes the last element at the end of the vector.
bool remove(AsyncTask *task)
Removes the indicated task from the active queue.
A class to manage a loose queue of isolated tasks, which can be performed either synchronously (in th...
size_type_0 size() const
Returns the number of elements in the ordered vector.
void start_threads()
Starts any requested threads to service the tasks on the queue.
void cleanup()
Stops all threads and messily empties the task list.
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
bool remove_task_chain(const string &name)
Removes the AsyncTaskChain of the indicated name.
void add_task(AsyncTask *task)
Adds a new AsyncTask to the collection.
A list of tasks, for instance as returned by some of the AsyncTaskManager query functions.
AsyncTaskCollection find_tasks_matching(const GlobPattern &pattern) const
Returns the list of tasks found whose name matches the indicated glob pattern, e.g.
double get_next_wake_time() const
Returns the scheduled time (on the manager&#39;s clock) of the next sleeping task, on any task chain...
AsyncTaskCollection get_tasks() const
Returns the set of tasks that are active or sleeping on the task manager, at the time of the call...
AsyncTaskCollection get_sleeping_tasks() const
Returns the set of tasks that are sleeping (and not active) on the task manager, at the time of the c...
A lightweight C++ object whose constructor calls acquire() and whose destructor calls release() on a ...
Definition: mutexHolder.h:29
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
AsyncTask * get_task(int index) const
Returns the nth AsyncTask in the collection.
bool empty() const
Returns true if the ordered vector is empty, false otherwise.
void notify_all()
Informs all of the other threads who are currently blocked on wait() that the relevant condition has ...
bool has_task(AsyncTask *task) const
Returns true if the indicated task has been added to this AsyncTaskManager, false otherwise...
A base class for all things which can have a name.
Definition: namable.h:29
AsyncTask * find_task(const string &name) const
Returns the first task found with the indicated name, or NULL if there is no task with the indicated ...
void acquire() const
Grabs the mutex if it is available.
Definition: mutexDirect.I:70
void wait_for_tasks()
Blocks until the task list is empty.
void stop_threads()
Stops any threads that are currently running.
AsyncTaskChain * get_task_chain(int n) const
Returns the nth task chain.
void add(AsyncTask *task)
Adds the indicated task to the active queue.
A ClockObject keeps track of elapsed real time and discrete time.
Definition: clockObject.h:66
void add_tasks_from(const AsyncTaskCollection &other)
Adds all the AsyncTasks indicated in the other collection to this task.
string get_const_prefix() const
Returns the initial part of the pattern before the first glob character.
Definition: globPattern.cxx:57
The AsyncTaskChain is a subset of the AsyncTaskManager.
AsyncTaskCollection get_active_tasks() const
Returns the set of tasks that are active (and not sleeping) on the task manager, at the time of the c...
int get_num_task_chains() const
Returns the number of different task chains.
int get_num_tasks() const
Returns the number of AsyncTasks in the collection.
void ref() const
Explicitly increments the reference count.
void local_object()
This function should be called, once, immediately after creating a new instance of some ReferenceCoun...
This class represents a concrete task performed by an AsyncManager.
Definition: asyncTask.h:43
AsyncTaskCollection find_tasks(const string &name) const
Returns the list of tasks found with the indicated name.
AsyncTaskChain * find_task_chain(const string &name)
Searches a new AsyncTaskChain of the indicated name and returns it if it exists, or NULL otherwise...
void release() const
Releases the mutex.
Definition: mutexDirect.I:99
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
This class can be used to test for string matches against standard Unix-shell filename globbing conve...
Definition: globPattern.h:37
void poll()
Runs through all the tasks in the task list, once, if the task manager is running in single-threaded ...