Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members

FXThread.h

Go to the documentation of this file.
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 

Copyright © 1997-2009 Jeroen van der Zijp