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