Blender V2.61 - r43446
|
00001 /* 00002 * Copyright 2011, Blender Foundation. 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 #ifndef __UTIL_THREAD_H__ 00020 #define __UTIL_THREAD_H__ 00021 00022 #include <boost/thread.hpp> 00023 #include <queue> 00024 00025 CCL_NAMESPACE_BEGIN 00026 00027 #if 0 00028 00029 /* Use STL for threading */ 00030 00031 using std::thread; 00032 using std::thread_mutex; 00033 typedef std::lock_guard thread_scoped_lock; 00034 using std::condition_variable; 00035 00036 #else 00037 00038 /* Use boost for threading */ 00039 00040 using boost::thread; 00041 typedef boost::mutex thread_mutex; 00042 typedef boost::mutex::scoped_lock thread_scoped_lock; 00043 typedef boost::condition_variable thread_condition_variable; 00044 00045 #endif 00046 00047 /* Thread Safe Queue to pass tasks from one thread to another. Tasks should be 00048 * pushed into the queue, while the worker thread waits to pop the next task 00049 * off the queue. Once all tasks are into the queue, calling stop() will stop 00050 * the worker threads from waiting for more tasks once all tasks are done. */ 00051 00052 template<typename T> class ThreadQueue 00053 { 00054 public: 00055 ThreadQueue() 00056 { 00057 tot = 0; 00058 tot_done = 0; 00059 do_stop = false; 00060 do_cancel = false; 00061 } 00062 00063 /* Main thread functions */ 00064 00065 /* push a task to be executed */ 00066 void push(const T& value) 00067 { 00068 thread_scoped_lock lock(queue_mutex); 00069 queue.push(value); 00070 tot++; 00071 lock.unlock(); 00072 00073 queue_cond.notify_one(); 00074 } 00075 00076 /* wait until all tasks are done */ 00077 void wait_done() 00078 { 00079 thread_scoped_lock lock(done_mutex); 00080 00081 while(tot_done != tot) 00082 done_cond.wait(lock); 00083 } 00084 00085 /* stop all worker threads */ 00086 void stop() 00087 { 00088 clear(); 00089 do_stop = true; 00090 queue_cond.notify_all(); 00091 } 00092 00093 /* cancel all tasks, but keep worker threads running */ 00094 void cancel() 00095 { 00096 clear(); 00097 do_cancel = true; 00098 wait_done(); 00099 do_cancel = false; 00100 } 00101 00102 /* Worker thread functions 00103 * 00104 * while(queue.worker_wait_pop(task)) { 00105 * for(..) { 00106 * ... do work ... 00107 * 00108 * if(queue.worker_cancel()) 00109 * break; 00110 * } 00111 * 00112 * queue.worker_done(); 00113 * } 00114 */ 00115 00116 bool worker_wait_pop(T& value) 00117 { 00118 thread_scoped_lock lock(queue_mutex); 00119 00120 while(queue.empty() && !do_stop) 00121 queue_cond.wait(lock); 00122 00123 if(queue.empty()) 00124 return false; 00125 00126 value = queue.front(); 00127 queue.pop(); 00128 00129 return true; 00130 } 00131 00132 void worker_done() 00133 { 00134 thread_scoped_lock lock(done_mutex); 00135 tot_done++; 00136 lock.unlock(); 00137 00138 assert(tot_done <= tot); 00139 00140 done_cond.notify_all(); 00141 } 00142 00143 bool worker_cancel() 00144 { 00145 return do_cancel; 00146 } 00147 00148 protected: 00149 void clear() 00150 { 00151 thread_scoped_lock lock(queue_mutex); 00152 00153 while(!queue.empty()) { 00154 thread_scoped_lock done_lock(done_mutex); 00155 tot_done++; 00156 done_lock.unlock(); 00157 00158 queue.pop(); 00159 } 00160 00161 done_cond.notify_all(); 00162 } 00163 00164 std::queue<T> queue; 00165 thread_mutex queue_mutex; 00166 thread_mutex done_mutex; 00167 thread_condition_variable queue_cond; 00168 thread_condition_variable done_cond; 00169 volatile bool do_stop; 00170 volatile bool do_cancel; 00171 volatile int tot, tot_done; 00172 }; 00173 00174 /* Thread Local Storage 00175 * 00176 * Boost implementation is a bit slow, and Mac OS X __thread is not supported 00177 * but the pthreads implementation is optimized, so we use these macros. */ 00178 00179 #ifdef __APPLE__ 00180 00181 #define tls_ptr(type, name) \ 00182 pthread_key_t name 00183 #define tls_set(name, value) \ 00184 pthread_setspecific(name, value) 00185 #define tls_get(type, name) \ 00186 ((type*)pthread_getspecific(name)) 00187 #define tls_create(type, name) \ 00188 pthread_key_create(&name, NULL) 00189 #define tls_delete(type, name) \ 00190 pthread_key_delete(name); 00191 00192 #else 00193 00194 #ifdef __WIN32 00195 #define __thread __declspec(thread) 00196 #endif 00197 00198 #define tls_ptr(type, name) \ 00199 __thread type *name 00200 #define tls_set(name, value) \ 00201 name = value 00202 #define tls_get(type, name) \ 00203 name 00204 #define tls_create(type, name) 00205 #define tls_delete(type, name) 00206 00207 #endif 00208 00209 CCL_NAMESPACE_END 00210 00211 #endif /* __UTIL_THREAD_H__ */ 00212