![]() |
Main Page Class Hierarchy Alphabetical List Compound List File List Compound Members
![]() |
00001 /******************************************************************************** 00002 * * 00003 * M u l i t h r e a d i n g S u p p o r t * 00004 * * 00005 ********************************************************************************* 00006 * Copyright (C) 2004,2009 by Jeroen van der Zijp. All Rights Reserved. * 00007 ********************************************************************************* 00008 * This library is free software; you can redistribute it and/or modify * 00009 * it under the terms of the GNU Lesser General Public License as published by * 00010 * the Free Software Foundation; either version 3 of the License, or * 00011 * (at your option) any later version. * 00012 * * 00013 * This library is distributed in the hope that it will be useful, * 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00016 * GNU Lesser General Public License for more details. * 00017 * * 00018 * You should have received a copy of the GNU Lesser General Public License * 00019 * along with this program. If not, see <http://www.gnu.org/licenses/> * 00020 ********************************************************************************* 00021 * $Id: FXThread.h,v 1.82 2009/01/06 13:07:28 fox Exp $ * 00022 ********************************************************************************/ 00023 #ifndef FXTHREAD_H 00024 #define FXTHREAD_H 00025 00026 namespace FX { 00027 00028 00029 /// Thread ID type 00030 #ifndef WIN32 00031 typedef unsigned long FXThreadID; 00032 #else 00033 typedef void* FXThreadID; 00034 #endif 00035 00036 00037 /// Thread-local storage key 00038 typedef FXuint FXThreadStorageKey; 00039 00040 00041 class FXCondition; 00042 00043 00044 /** 00045 * FXMutex provides a mutex which can be used to enforce critical 00046 * sections around updates of data shared by multiple threads. 00047 */ 00048 class FXAPI FXMutex { 00049 friend class FXCondition; 00050 private: 00051 volatile FXuval data[24]; 00052 private: 00053 FXMutex(const FXMutex&); 00054 FXMutex &operator=(const FXMutex&); 00055 public: 00056 00057 /// Initialize the mutex 00058 FXMutex(FXbool recursive=false); 00059 00060 /// Lock the mutex 00061 void lock(); 00062 00063 /// Return true if succeeded locking the mutex 00064 FXbool trylock(); 00065 00066 /// Return true if mutex is already locked 00067 FXbool locked(); 00068 00069 /// Unlock mutex 00070 void unlock(); 00071 00072 /// Delete the mutex 00073 ~FXMutex(); 00074 }; 00075 00076 00077 /** 00078 * An easy way to establish a correspondence between a C++ scope 00079 * and a critical section is to simply declare an FXMutexLock 00080 * at the beginning of the scope. 00081 * The mutex will be automatically released when the scope is 00082 * left (either by natural means or by means of an exception. 00083 */ 00084 class FXAPI FXMutexLock { 00085 private: 00086 FXMutex& mtx; 00087 private: 00088 FXMutexLock(); 00089 FXMutexLock(const FXMutexLock&); 00090 FXMutexLock& operator=(const FXMutexLock&); 00091 public: 00092 00093 /// Construct & lock associated mutex 00094 FXMutexLock(FXMutex& m):mtx(m){ lock(); } 00095 00096 /// Return reference to associated mutex 00097 FXMutex& mutex(){ return mtx; } 00098 00099 /// Lock mutex 00100 void lock(){ mtx.lock(); } 00101 00102 /// Return true if succeeded locking the mutex 00103 FXbool trylock(){ return mtx.trylock(); } 00104 00105 /// Return true if mutex is already locked 00106 FXbool locked(){ return mtx.locked(); } 00107 00108 /// Unlock mutex 00109 void unlock(){ mtx.unlock(); } 00110 00111 /// Destroy and unlock associated mutex 00112 ~FXMutexLock(){ unlock(); } 00113 }; 00114 00115 00116 /** 00117 * FXSpinLock can be used to provide safe access to very small 00118 * critical sections. It is cheaper than FXMutex, but unlike 00119 * FXMutex, threads which are unable to obtain the lock will 00120 * not block, but spin in a tight loop until the lock can be 00121 * obtained. 00122 */ 00123 class FXAPI FXSpinLock { 00124 private: 00125 volatile FXuval data[4]; 00126 private: 00127 FXSpinLock(const FXSpinLock&); 00128 FXSpinLock &operator=(const FXSpinLock&); 00129 public: 00130 00131 /// Initialize the spinlock 00132 FXSpinLock(); 00133 00134 /// Lock the mutex 00135 void lock(); 00136 00137 /// Return true if succeeded locking the spinlock 00138 FXbool trylock(); 00139 00140 /// Return true if spinlock is already locked 00141 FXbool locked(); 00142 00143 /// Unlock spinlock 00144 void unlock(); 00145 00146 /// Delete the spinlock 00147 ~FXSpinLock(); 00148 }; 00149 00150 00151 /** 00152 * A semaphore allows for protection of a resource that can 00153 * be accessed by a fixed number of simultaneous threads. 00154 */ 00155 class FXAPI FXSemaphore { 00156 private: 00157 volatile FXuval data[16]; 00158 private: 00159 FXSemaphore(const FXSemaphore&); 00160 FXSemaphore& operator=(const FXSemaphore&); 00161 public: 00162 00163 /// Initialize semaphore with given count 00164 FXSemaphore(FXint initial=1); 00165 00166 /// Decrement semaphore 00167 void wait(); 00168 00169 /// Non-blocking semaphore decrement; return true if locked 00170 FXbool trywait(); 00171 00172 /// Increment semaphore 00173 void post(); 00174 00175 /// Delete semaphore 00176 ~FXSemaphore(); 00177 }; 00178 00179 00180 /** 00181 * A condition allows one or more threads to synchronize 00182 * to an event. When a thread calls wait, the associated 00183 * mutex is unlocked while the thread is blocked. When the 00184 * condition becomes signaled, the associated mutex is 00185 * locked and the thread(s) are reawakened. 00186 */ 00187 class FXAPI FXCondition { 00188 private: 00189 volatile FXuval data[12]; 00190 private: 00191 FXCondition(const FXCondition&); 00192 FXCondition& operator=(const FXCondition&); 00193 public: 00194 00195 /// Initialize the condition 00196 FXCondition(); 00197 00198 /** 00199 * Wait until condition becomes signalled, using given mutex, 00200 * which must already have been locked prior to this call. 00201 * Return true if the wait ended due to the condition being 00202 * signalled through signal() or broadcast(), and false if the 00203 * wait was interrupted or some error occurred. 00204 */ 00205 FXbool wait(FXMutex& mtx); 00206 00207 /** 00208 * Wait until condition becomes signalled, using given mutex, 00209 * which must already have been locked prior to this call. 00210 * Return true if the wait ended due to the condition being 00211 * signalled through signal() or broadcast(), and false if the 00212 * wait timed out, was interrupted, or some other error occurred. 00213 * The absolute time is specified in nanoseconds since the Epoch 00214 * (Jan 1, 1970). 00215 */ 00216 FXbool wait(FXMutex& mtx,FXTime nsec); 00217 00218 /** 00219 * Wake or unblock a single blocked thread 00220 */ 00221 void signal(); 00222 00223 /** 00224 * Wake or unblock all blocked threads 00225 */ 00226 void broadcast(); 00227 00228 /// Delete the condition 00229 ~FXCondition(); 00230 }; 00231 00232 00233 /** 00234 * A read / write lock allows multiple readers but only a single 00235 * writer. 00236 */ 00237 class FXAPI FXReadWriteLock { 00238 private: 00239 volatile FXuval data[32]; 00240 private: 00241 FXReadWriteLock(const FXReadWriteLock&); 00242 FXReadWriteLock &operator=(const FXReadWriteLock&); 00243 public: 00244 00245 /// Initialize the read/write lock 00246 FXReadWriteLock(); 00247 00248 /// Acquire read lock for read/write lock 00249 void readLock(); 00250 00251 /// Try to acquire read lock for read/write lock 00252 bool tryReadLock(); 00253 00254 /// Unlock read lock 00255 void readUnlock(); 00256 00257 /// Acquire write lock for read/write mutex 00258 void writeLock(); 00259 00260 /// Try to acquire write lock for read/write lock 00261 bool tryWriteLock(); 00262 00263 /// Unlock write mutex 00264 void writeUnlock(); 00265 00266 /// Delete the read/write lock 00267 ~FXReadWriteLock(); 00268 }; 00269 00270 00271 /** 00272 * FXRunnable represents a generic runnable thing. It serves primarily 00273 * as a base class for FXThread and tasks in FXThreadPool. 00274 */ 00275 class FXAPI FXRunnable { 00276 private: 00277 FXRunnable(const FXRunnable&); 00278 FXRunnable &operator=(const FXRunnable&); 00279 public: 00280 00281 /// Construct a runnable 00282 FXRunnable(){} 00283 00284 /// Subclasses of FXRunnable overload this function to perform actual work 00285 virtual FXint run() = 0; 00286 00287 /// Destroy a runnable 00288 virtual ~FXRunnable(){} 00289 }; 00290 00291 00292 /** 00293 * Automatically generated thread-local storage key. 00294 * This class manages a thread-local storage key, generating 00295 * a new one when constructed, and deleting the storage key when 00296 * destroyed. 00297 * These keys can be used just like FXThreadStorageKey itself by 00298 * virtue of the conversion operator. Note that no assignment 00299 * or copy-constructors have been defined; thus each instance of 00300 * this class represents a unique thread-local storage key. 00301 */ 00302 class FXAPI FXAutoThreadStorageKey { 00303 private: 00304 FXThreadStorageKey value; 00305 private: 00306 FXAutoThreadStorageKey(const FXAutoThreadStorageKey&); 00307 FXAutoThreadStorageKey &operator=(const FXAutoThreadStorageKey&); 00308 public: 00309 00310 /// Acquire a unique thread-local storage key 00311 FXAutoThreadStorageKey(); 00312 00313 /// Return the thread-local storage key 00314 operator FXThreadStorageKey() const { return value; } 00315 00316 /// Release thread-local storage key 00317 ~FXAutoThreadStorageKey(); 00318 }; 00319 00320 00321 /** 00322 * FXThread provides system-independent support for threads. 00323 * Subclasses must implement the run() function do implement 00324 * the desired functionality of the thread. 00325 * The storage of the FXThread object is to be managed by the 00326 * calling thread, not by the thread itself. 00327 */ 00328 class FXAPI FXThread : public FXRunnable { 00329 private: 00330 volatile FXThreadID tid; 00331 volatile FXbool busy; 00332 private: 00333 static FXAutoThreadStorageKey selfKey; 00334 private: 00335 FXThread(const FXThread&); 00336 FXThread &operator=(const FXThread&); 00337 #ifdef WIN32 00338 static unsigned int CALLBACK function(void*); 00339 #else 00340 static void* function(void*); 00341 #endif 00342 protected: 00343 static void self(FXThread* t); 00344 public: 00345 00346 /// Thread priority levels 00347 enum Priority { 00348 PriorityError=-1, /// Failed to get priority 00349 PriorityDefault, /// Default scheduling priority 00350 PriorityMinimum, /// Minimum scheduling priority 00351 PriorityLower, /// Lower scheduling priority 00352 PriorityMedium, /// Medium priority 00353 PriorityHigher, /// Higher scheduling priority 00354 PriorityMaximum /// Maximum scheduling priority 00355 }; 00356 00357 /// Thread scheduling policies 00358 enum Policy { 00359 PolicyError=-1, /// Failed to get policy 00360 PolicyDefault, /// Default scheduling 00361 PolicyFifo, /// First in, first out scheduling 00362 PolicyRoundRobin /// Round-robin scheduling 00363 }; 00364 00365 public: 00366 00367 /// Initialize thread object. 00368 FXThread(); 00369 00370 /** 00371 * Return handle of this thread object. 00372 * This handle is valid in the context of the thread which 00373 * called start(). 00374 */ 00375 FXThreadID id() const; 00376 00377 /** 00378 * Return true if this thread is running. 00379 */ 00380 FXbool running() const; 00381 00382 /** 00383 * Start thread; the thread is started as attached. 00384 * The thread is given stacksize for its stack; a value of 00385 * zero for stacksize will give it the default stack size. 00386 * This invokes the run() function in the context of the new 00387 * thread. 00388 */ 00389 FXbool start(unsigned long stacksize=0); 00390 00391 /** 00392 * Suspend calling thread until thread is done. The FXThreadID is 00393 * reset back to zero. 00394 */ 00395 FXbool join(); 00396 00397 /** 00398 * Suspend calling thread until thread is done, and set code to the 00399 * return value of run() or the argument passed into exit(). The 00400 * FXThreadID is reset back to zero. 00401 * If an exception happened in the thread, return -1. 00402 */ 00403 FXbool join(FXint& code); 00404 00405 /** 00406 * Cancel the thread, stopping it immediately, running or not. 00407 * If the calling thread is this thread, nothing happens. 00408 * It is probably better to wait until it is finished, in case the 00409 * thread currently holds mutexes. 00410 * The FXThreadID is reset back to zero after the thread has been 00411 * stopped. 00412 */ 00413 FXbool cancel(); 00414 00415 /** 00416 * Detach thread, so that a no join() is necessary to harvest the 00417 * resources of this thread. The thread continues to run until 00418 * normal completion. 00419 */ 00420 FXbool detach(); 00421 00422 /** 00423 * Exit the calling thread. 00424 * No destructors are invoked for objects on thread's stack; 00425 * to invoke destructors, throw an exception instead. 00426 */ 00427 static void exit(FXint code=0); 00428 00429 /** 00430 * Make the thread yield its time quantum. 00431 */ 00432 static void yield(); 00433 00434 /** 00435 * Return time in nanoseconds since Epoch (Jan 1, 1970). 00436 */ 00437 static FXTime time(); 00438 00439 /** 00440 * Make the calling thread sleep for a number of nanoseconds. 00441 */ 00442 static void sleep(FXTime nsec); 00443 00444 /** 00445 * Wake at appointed time specified in nanoseconds since Epoch. 00446 */ 00447 static void wakeat(FXTime nsec); 00448 00449 /** 00450 * Return pointer to the FXThread instance associated 00451 * with the calling thread; it returns NULL for the main 00452 * thread and all threads not created by FOX. 00453 */ 00454 static FXThread* self(); 00455 00456 /** 00457 * Return thread id of calling thread. 00458 */ 00459 static FXThreadID current(); 00460 00461 /** 00462 * Return number of available processors in the system. 00463 */ 00464 static FXint processors(); 00465 00466 /** 00467 * Generate new thread local storage key. 00468 */ 00469 static FXThreadStorageKey createStorageKey(); 00470 00471 /** 00472 * Dispose of thread local storage key. 00473 */ 00474 static void deleteStorageKey(FXThreadStorageKey key); 00475 00476 /** 00477 * Get thread local storage pointer using key. 00478 */ 00479 static void* getStorage(FXThreadStorageKey key); 00480 00481 /** 00482 * Set thread local storage pointer using key. 00483 */ 00484 static void setStorage(FXThreadStorageKey key,void* ptr); 00485 00486 /** 00487 * Set thread scheduling priority. 00488 */ 00489 FXbool priority(Priority prio); 00490 00491 /** 00492 * Return thread scheduling priority. 00493 */ 00494 Priority priority() const; 00495 00496 /** 00497 * Set thread scheduling policy. 00498 */ 00499 FXbool policy(Policy plcy); 00500 00501 /** 00502 * Get thread scheduling policy. 00503 */ 00504 Policy policy() const; 00505 00506 /** 00507 * Suspend thread; return true if success. 00508 */ 00509 FXbool suspend(); 00510 00511 /** 00512 * Resume thread; return true if success. 00513 */ 00514 FXbool resume(); 00515 00516 /** 00517 * Destroy the thread immediately, running or not. 00518 * It is probably better to wait until it is finished, in case 00519 * the thread currently holds mutexes. 00520 */ 00521 virtual ~FXThread(); 00522 }; 00523 00524 } 00525 00526 #endif 00527
![]() |