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,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 

Copyright © 1997-2010 Jeroen van der Zijp