1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef __UTIL_TASK_H__
18 #define __UTIL_TASK_H__
19 
20 #include "util/util_list.h"
21 #include "util/util_string.h"
22 #include "util/util_tbb.h"
23 #include "util/util_thread.h"
24 #include "util/util_vector.h"
25 
26 CCL_NAMESPACE_BEGIN
27 
28 class TaskPool;
29 class TaskScheduler;
30 
31 typedef function<void(void)> TaskRunFunction;
32 
33 /* Task Pool
34  *
35  * Pool of tasks that will be executed by the central TaskScheduler.For each
36  * pool, we can wait for all tasks to be done, or cancel them before they are
37  * done.
38  *
39  * TaskRunFunction may be created with std::bind or lambda expressions. */
40 
41 class TaskPool {
42  public:
43   struct Summary {
44     /* Time spent to handle all tasks. */
45     double time_total;
46 
47     /* Number of all tasks handled by this pool. */
48     int num_tasks_handled;
49 
50     /* A full multi-line description of the state of the pool after
51      * all work is done.
52      */
53     string full_report() const;
54   };
55 
56   TaskPool();
57   ~TaskPool();
58 
59   void push(TaskRunFunction &&task);
60 
61   void wait_work(Summary *stats = NULL); /* work and wait until all tasks are done */
62   void cancel(); /* cancel all tasks and wait until they are no longer executing */
63 
64   static bool canceled(); /* For worker threads, test if current task pool canceled. */
65 
66  protected:
67   tbb::task_group tbb_group;
68 
69   /* ** Statistics ** */
70 
71   /* Time time stamp of first task pushed. */
72   double start_time;
73 
74   /* Number of all tasks pushed to the pool. Cleared after wait_work() and cancel(). */
75   int num_tasks_pushed;
76 };
77 
78 /* Task Scheduler
79  *
80  * Central scheduler that holds running threads ready to execute tasks. A singe
81  * queue holds the task from all pools. */
82 
83 class TaskScheduler {
84  public:
85   static void init(int num_threads = 0);
86   static void exit();
87   static void free_memory();
88 
89   /* Approximate number of threads that will work on task, which may be lower
90    * or higher than the actual number of threads. Use as little as possible and
91    * leave splitting up tasks to the scheduler.. */
92   static int num_threads();
93 
94  protected:
95   static thread_mutex mutex;
96   static int users;
97   static int active_num_threads;
98 
99 #ifdef WITH_TBB_GLOBAL_CONTROL
100   static tbb::global_control *global_control;
101 #endif
102 };
103 
104 /* Dedicated Task Pool
105  *
106  * Like a TaskPool, but will launch one dedicated thread to execute all tasks.
107  *
108  * The run callback that actually executes the task may be created like this:
109  * function_bind(&MyClass::task_execute, this, _1, _2) */
110 
111 class DedicatedTaskPool {
112  public:
113   DedicatedTaskPool();
114   ~DedicatedTaskPool();
115 
116   void push(TaskRunFunction &&run, bool front = false);
117 
118   void wait();   /* wait until all tasks are done */
119   void cancel(); /* cancel all tasks, keep worker thread running */
120 
121   bool canceled(); /* for worker thread, test if canceled */
122 
123  protected:
124   void num_decrease(int done);
125   void num_increase();
126 
127   void thread_run();
128   bool thread_wait_pop(TaskRunFunction &task);
129 
130   void clear();
131 
132   thread_mutex num_mutex;
133   thread_condition_variable num_cond;
134 
135   list<TaskRunFunction> queue;
136   thread_mutex queue_mutex;
137   thread_condition_variable queue_cond;
138 
139   int num;
140   bool do_cancel;
141   bool do_exit;
142 
143   thread *worker_thread;
144 };
145 
146 CCL_NAMESPACE_END
147 
148 #endif
149