QThread.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) 2002-2006 by Niall Douglas.   All Rights Reserved.       *
00007 *       NOTE THAT I DO NOT PERMIT ANY OF MY CODE TO BE PROMOTED TO THE GPL      *
00008 *********************************************************************************
00009 * This code is free software; you can redistribute it and/or modify it under    *
00010 * the terms of the GNU Library General Public License v2.1 as published by the  *
00011 * Free Software Foundation EXCEPT that clause 3 does not apply ie; you may not  *
00012 * "upgrade" this code to the GPL without my prior written permission.           *
00013 * Please consult the file "License_Addendum2.txt" accompanying this file.       *
00014 *                                                                               *
00015 * This code is distributed in the hope that it will be useful,                  *
00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                          *
00018 *********************************************************************************
00019 * $Id:                                                                          *
00020 ********************************************************************************/
00021 
00022 #ifndef QTHREAD_H
00023 #define QTHREAD_H
00024 
00025 #include "FXProcess.h"
00026 
00027 namespace FX {
00028 
00045 #ifdef FXINLINE_MUTEX_IMPLEMENTATION
00046  #define QMUTEX_FXAPI
00047  #define QMUTEX_GLOBALS_FXAPI FXAPI
00048  // Testing has found that force inlining public declarations makes
00049  // the code go slower so we leave it up to the compiler
00050  #define QMUTEX_INLINEI inline FXFORCEINLINE
00051  #define QMUTEX_INLINEP inline
00052 #else
00053  #define QMUTEX_FXAPI FXAPI
00054  #define QMUTEX_GLOBALS_FXAPI
00055  #define QMUTEX_INLINEI FXFORCEINLINE   // internally inlined inside QThread.cxx
00056  #define QMUTEX_INLINEP             // publicly inlined
00057 #endif
00058 
00100 class QMUTEX_FXAPI FXAtomicInt
00101 {
00102     volatile long lock;     // Unused on systems with atomic increment/decrement/exchange-compare
00103     volatile int value;
00104     volatile int value2;    // Used for padding
00105     friend class QMutex;
00106     friend class QShrdMemMutex;
00107     QMUTEX_INLINEI FXDLLLOCAL int get() const throw();
00108     QMUTEX_INLINEI FXDLLLOCAL int set(int i) throw();
00109     QMUTEX_INLINEI FXDLLLOCAL int incp() throw();
00110     QMUTEX_INLINEI FXDLLLOCAL int pinc() throw();
00111     QMUTEX_INLINEI FXDLLLOCAL int finc() throw();
00112     QMUTEX_INLINEI FXDLLLOCAL int inc(int i) throw();
00113     QMUTEX_INLINEI FXDLLLOCAL int decp() throw();
00114     QMUTEX_INLINEI FXDLLLOCAL int pdec() throw();
00115     QMUTEX_INLINEI FXDLLLOCAL int fdec() throw();
00116     QMUTEX_INLINEI FXDLLLOCAL int dec(int i) throw();
00117     QMUTEX_INLINEI FXDLLLOCAL int swapI(int newval) throw();
00118     QMUTEX_INLINEI FXDLLLOCAL int cmpXI(int compare, int newval) throw();
00119     QMUTEX_INLINEI FXDLLLOCAL int spinI(int count) throw();
00120 public:
00122     QMUTEX_INLINEP FXAtomicInt(int i=0) throw() : lock(0), value(i), value2(0) { }
00123     QMUTEX_INLINEP FXAtomicInt(const FXAtomicInt &o) throw() : lock(0), value(o.value), value2(0) { }
00124     QMUTEX_INLINEP FXAtomicInt &operator=(const FXAtomicInt &o) throw() { lock=0; value=o.value; return *this; }
00126     QMUTEX_INLINEP operator int() const throw();
00128     QMUTEX_INLINEP int operator=(int i) throw();
00130     QMUTEX_INLINEP int operator++(int) throw();
00132     QMUTEX_INLINEP int operator++() throw();
00136     QMUTEX_INLINEP int fastinc() throw();
00138     QMUTEX_INLINEP int operator+=(int i) throw();
00140     QMUTEX_INLINEP int operator--(int) throw();
00142     QMUTEX_INLINEP int operator--() throw();
00146     QMUTEX_INLINEP int fastdec() throw();
00148     QMUTEX_INLINEP int operator-=(int i) throw();
00150     QMUTEX_INLINEP int swap(int newval) throw();
00152     QMUTEX_INLINEP int cmpX(int compare, int newval) throw();
00153 };
00154 
00188 class QMUTEX_FXAPI QShrdMemMutex
00189 {
00190     FXAtomicInt lockvar;
00191     FXuint timeout;     // =0 for infinite, =timeout+1 otherwise
00192 public:
00194     QMUTEX_INLINEP QShrdMemMutex(FXuint _timeout=1000) : timeout(_timeout+1) { }
00196     QMUTEX_INLINEP FXuint timeOut() const throw() { return timeout-1; }
00198     QMUTEX_INLINEP void setTimeOut(FXuint to) throw() { timeout=to+1; }
00200     QMUTEX_INLINEP void lock();
00202     QMUTEX_INLINEP void unlock() throw() { lockvar=0; }
00204     QMUTEX_INLINEP bool tryLock() throw();
00205 };
00206 
00313 struct QMutexPrivate;
00314 class QMUTEX_FXAPI QMutex
00315 {
00316     QMutexPrivate *p;
00317     QMutex(const QMutex &);
00318     QMutex &operator=(const QMutex &);
00319     friend class QRWMutex;
00320     QMUTEX_INLINEI FXDLLLOCAL void int_lock();
00321     QMUTEX_INLINEI FXDLLLOCAL void int_unlock();
00322 public:
00324     QMUTEX_INLINEP QMutex(FXuint spinCount=4000);
00325     QMUTEX_INLINEP ~QMutex();
00327     QMUTEX_INLINEP bool isLocked() const;
00331     QMUTEX_INLINEP FXbool locked() const { return (FXbool) isLocked(); }
00333     QMUTEX_INLINEP FXuint spinCount() const;
00335     QMUTEX_INLINEP void setSpinCount(FXuint c);
00340     QMUTEX_INLINEP void lock();
00345     QMUTEX_INLINEP void unlock();
00349     QMUTEX_INLINEP bool tryLock();
00353     QMUTEX_INLINEP FXbool trylock() { return (FXbool) tryLock(); }
00356     QMUTEX_INLINEP static bool setMutexDebugYield(bool v);
00357 };
00358 
00359 
00384 class QWaitConditionPrivate;
00385 class FXAPI QWaitCondition
00386 {
00387     QWaitConditionPrivate *p;
00388     bool isSignalled, isAutoReset;
00389     QWaitCondition(const QWaitCondition &);
00390     QWaitCondition &operator=(const QWaitCondition &);
00391 public:
00395     QWaitCondition(bool autoreset=false, bool initialstate=false);
00396     ~QWaitCondition();
00400     bool wait(FXuint time=FXINFINITE) ;
00402     void wakeOne () ;
00409     void wakeAll () ;
00411     void reset();
00413     bool signalled() const { return isSignalled; }
00414 };
00415 
00451 class QRWMutexPrivate;
00452 class QMtxHold;
00453 class FXAPI QRWMutex
00454 {
00455     QRWMutexPrivate *p;
00456     QRWMutex(const QRWMutex &);
00457     QRWMutex &operator=(const QRWMutex &);
00458 public:
00459     enum LockedState
00460     {
00461         Unlocked=0,
00462         ReadOnly,
00463         ReadWrite
00464     };
00465 private:
00466     LockedState lockedstate;
00467 public:
00468     QRWMutex();
00469     ~QRWMutex();
00471     FXuint spinCount() const;
00473     void setSpinCount(FXuint c);
00492     bool lock(bool write=true);
00497     void unlock(bool write=true);
00499     LockedState isLocked() const { return lockedstate; }
00503     bool trylock(bool write);
00504 private:
00506     bool prefersReaders() const;
00508     void setReaderPreference(bool);
00509     inline FXDLLLOCAL bool _lock(QMtxHold &h, bool write);
00510 };
00511 
00522 class QMtxHold
00523 {
00524     FXuint flags;
00525     bool locklost;
00526     union {
00527         QMutex *mutex;
00528         QRWMutex *rwmutex;
00529         QShrdMemMutex *shrdmutex;
00530     };
00531 
00532     QMtxHold(const QMtxHold &);
00533     QMtxHold &operator=(const QMtxHold &);
00534 public:
00536     enum Flags
00537     {
00538         LockAndUnlock=0,        
00539         UnlockAndRelock=1,      
00540         AcceptNullMutex=2,      
00541 
00542         IsShrdMutex=(1<<26),
00543         IsRWMutex=(1<<27),
00544         IsLocked=(1<<28),
00545         IsRWMutexWrite=(1<<29)
00546     };
00548     FXFORCEINLINE QMtxHold(const QMutex *m, FXuint _flags=LockAndUnlock)
00549         : flags(_flags), locklost(false)
00550     {
00551         mutex=const_cast<QMutex *>(m);
00552         if((flags & AcceptNullMutex) && !mutex) return;
00553         if(flags & UnlockAndRelock) mutex->unlock(); else mutex->lock();
00554         flags|=IsLocked;
00555     }
00557     FXFORCEINLINE QMtxHold(const QMutex &m, FXuint _flags=LockAndUnlock)
00558         : flags(_flags), locklost(false)
00559     {
00560         mutex=const_cast<QMutex *>(&m);
00561         if(flags & UnlockAndRelock) mutex->unlock(); else mutex->lock();
00562         flags|=IsLocked;
00563     }
00565     FXFORCEINLINE QMtxHold(const QRWMutex *m, bool write=true, FXuint _flags=LockAndUnlock)
00566         : flags(_flags|IsRWMutex|(write ? IsRWMutexWrite : 0)), locklost(false)
00567     {
00568         rwmutex=const_cast<QRWMutex *>(m);
00569         if((flags & AcceptNullMutex) && !rwmutex) return;
00570         locklost=rwmutex->lock(!!(flags & IsRWMutexWrite));
00571         flags|=IsLocked;
00572     }
00574     FXFORCEINLINE QMtxHold(const QRWMutex &m, bool write=true, FXuint _flags=LockAndUnlock)
00575         : flags(_flags|IsRWMutex|(write ? IsRWMutexWrite : 0)), locklost(false)
00576     {
00577         rwmutex=const_cast<QRWMutex *>(&m);
00578         locklost=rwmutex->lock(!!(flags & IsRWMutexWrite));
00579         flags|=IsLocked;
00580     }
00582     FXFORCEINLINE QMtxHold(const QShrdMemMutex *m, FXuint _flags=LockAndUnlock)
00583         : flags(_flags|IsShrdMutex), locklost(false)
00584     {
00585         shrdmutex=const_cast<QShrdMemMutex *>(m);
00586         if((flags & AcceptNullMutex) && !shrdmutex) return;
00587         if(flags & UnlockAndRelock) shrdmutex->unlock(); else shrdmutex->lock();
00588         flags|=IsLocked;
00589     }
00591     FXFORCEINLINE QMtxHold(const QShrdMemMutex &m, FXuint _flags=LockAndUnlock)
00592         : flags(_flags|IsShrdMutex), locklost(false)
00593     {
00594         shrdmutex=const_cast<QShrdMemMutex *>(&m);
00595         if(flags & UnlockAndRelock) shrdmutex->unlock(); else shrdmutex->lock();
00596         flags|=IsLocked;
00597     }
00599     FXFORCEINLINE void unlock()
00600     {
00601         if((flags & AcceptNullMutex) && !mutex) return;
00602         if(flags & IsLocked)
00603         {
00604             if(flags & IsRWMutex)
00605                 rwmutex->unlock(!!(flags & IsRWMutexWrite));
00606             else if(flags & IsShrdMutex)
00607             {
00608                 if(flags & UnlockAndRelock) shrdmutex->lock(); else shrdmutex->unlock();
00609             }
00610             else
00611             {
00612                 if(flags & UnlockAndRelock) mutex->lock(); else mutex->unlock();
00613             }
00614             flags&=~IsLocked;
00615         }
00616     }
00618     FXFORCEINLINE void relock()
00619     {
00620         if((flags & AcceptNullMutex) && !mutex && !rwmutex) return;
00621         if(!(flags & IsLocked))
00622         {
00623             if(flags & IsRWMutex)
00624                 locklost=rwmutex->lock(!!(flags & IsRWMutexWrite));
00625             else if(flags & IsShrdMutex)
00626             {
00627                 if(flags & UnlockAndRelock) shrdmutex->unlock(); else shrdmutex->lock();
00628             }
00629             else
00630             {
00631                 if(flags & UnlockAndRelock) mutex->unlock(); else mutex->lock();
00632             }
00633             flags|=IsLocked;
00634         }
00635     }
00637     FXFORCEINLINE bool lockLost() const { return locklost; }
00638     FXFORCEINLINE ~QMtxHold() { unlock(); }
00639 };
00640 
00641 // Needs to go here as QMtxHold needs to be defined
00642 namespace Generic {
00643 
00675 template<class type> struct lockedAccessor
00676 {
00677 private:
00678     QMtxHold *h;
00679     type &val;
00680 public:
00682     lockedAccessor(type &_val, const QMutex *m) : val(_val), h(0) { if(m) { FXERRHM(h=new QMtxHold(m)); } }
00684     lockedAccessor(type &_val, const QMutex &m) : val(_val), h(0) { FXERRHM(h=new QMtxHold(m)); }
00686     lockedAccessor(type &_val, const QRWMutex *m) : val(_val), h(0) { if(m) { FXERRHM(h=new QMtxHold(m)); } }
00688     lockedAccessor(type &_val, const QRWMutex &m) : val(_val), h(0) { FXERRHM(h=new QMtxHold(m)); }
00689 #ifndef HAVE_CPP0XRVALUEREFS
00690 #ifdef HAVE_CONSTTEMPORARIES
00691     lockedAccessor(const lockedAccessor &_o) : h(_o.h), val(_o.val)
00692     {
00693         lockedAccessor &o=const_cast<lockedAccessor &>(_o);
00694         o.h=0;
00695     }
00696     lockedAccessor &operator=(const lockedAccessor &_o)
00697     {
00698         lockedAccessor &o=const_cast<lockedAccessor &>(_o);
00699         this->~lockedAccessor();
00700         return *new(this) lockedAccessor(o);
00701     }
00702 #else
00703     lockedAccessor(lockedAccessor &o) : h(o.h), val(o.val)
00704     {
00705         o.h=0;
00706     }
00707     lockedAccessor &operator=(lockedAccessor &o)
00708     {
00709         this->~lockedAccessor();
00710         return *new(this) lockedAccessor(o);
00711     }
00712 #endif
00713 #else
00714 private:
00715     lockedAccessor(const lockedAccessor &); // disable copy constructor
00716     lockedAccessor &operator=(const lockedAccessor &_o);
00717 public:
00718     lockedAccessor(lockedAccessor &&o) : h(o.h), val(o.val)
00719     {
00720         o.h=0;
00721     }
00722     lockedAccessor &&operator=(lockedAccessor &&o)
00723     {
00724         this->~lockedAccessor();
00725         return *new(this) lockedAccessor(o);
00726     }
00727 #endif
00728     ~lockedAccessor()
00729     {
00730         FXDELETE(h);
00731     }
00732 
00734     type &operator*() const { return const_cast<type &>(val); }
00736     type *operator->() const { return const_cast<type *>(&val); }
00737 };
00738 } // namespace
00739 
00752 class FXZeroedWait
00753 {
00754     FXAtomicInt count;
00755     bool doChecks;
00756     QWaitCondition wc;
00757     void handleCount(int nc)
00758     {
00759         if(doChecks)
00760         {
00761             if(nc<0) FXERRG("Count should not be below zero", 0, FXERRH_ISDEBUG);
00762         }
00763         if(nc>0) wc.reset();
00764         else if(!nc) wc.wakeAll();
00765     }
00766 public:
00768     FXZeroedWait(int initcount=0) : count(initcount), doChecks(false), wc(false, !initcount) { }
00770     operator int() const { return count; }
00772     int operator=(int i)    { int c=(count=i);  handleCount(c);     return c; }
00774     int operator++(int)     { int c=count++;    handleCount(c+1);   return c; }
00776     int operator++()        { int c=++count;    handleCount(c);     return c; }
00778     int operator+=(int i)   { int c=(count+=i); handleCount(c);     return c; }
00780     int operator--(int)     { int c=count--;    handleCount(c-1);   return c; }
00782     int operator--()        { int c=--count;    handleCount(c); return c; }
00784     int operator-=(int i)   { int c=(count-=i); handleCount(c);     return c; }
00785 
00787     bool wait(FXuint time=FXINFINITE) { return wc.wait(time); }
00789     void setChecks(bool d) { doChecks=d; }
00790 };
00791 
00822 class QThreadLocalStorageBasePrivate;
00823 class FXAPI QThreadLocalStorageBase
00824 {
00825     QThreadLocalStorageBasePrivate *p;
00826     QThreadLocalStorageBase(const QThreadLocalStorageBase &);
00827     QThreadLocalStorageBase &operator=(const QThreadLocalStorageBase &);
00828 public:
00829     QThreadLocalStorageBase(void *initval=0);
00830     ~QThreadLocalStorageBase();
00832     void setPtr(void *val);
00834     void *getPtr() const;
00835 };
00836 template<class type> class QThreadLocalStorage : private QThreadLocalStorageBase
00837 {
00838 public:
00840     QThreadLocalStorage(type *initval=0) : QThreadLocalStorageBase(static_cast<void *>(initval)) { }
00844     type *operator=(type *a) { setPtr(static_cast<void *>(a)); return a; }
00848     operator type *() const { return static_cast<type *>(getPtr()); }
00849     type *operator ->() const { return static_cast<type *>(getPtr()); }
00850 };
00851 
00852 
00970 class QThreadPrivate;
00971 class FXAPI QThread
00972 {
00973     friend class QThreadPrivate;
00974     friend class FXPrimaryThread;
00975     const char *myname;
00976     FXuint magic;
00977     QThreadPrivate *p;
00978     bool isRunning, isFinished, isInCleanup;
00979     int termdisablecnt;
00980     QThread(const QThread &);
00981     QThread &operator=(const QThread &);
00982 public:
00984     enum ThreadScheduler
00985     {
00986         Auto=0,     
00987         InProcess,  
00988         InKernel    
00989     };
00993     QThread(const char *name=0, bool autodelete=false, FXuval stacksize=524288/*512Kb*/, ThreadScheduler schedloc=Auto);
00995     virtual ~QThread();
00997     const char *name() const throw() { return myname; }
00999     FXuval stackSize() const;
01008     void setStackSize(FXuval newsize);
01010     ThreadScheduler threadLocation() const;
01012     void setThreadLocation(ThreadScheduler threadloc);
01013 
01021     bool wait(FXuint time=FXINFINITE);
01029     void start(bool waitTillStarted=false) ;
01031     bool finished () const  throw(){ return isFinished; }
01033     bool running () const  throw(){ return isRunning; }
01035     bool inCleanup() const  throw(){ return isInCleanup; }
01037     bool isValid() const throw();
01041     bool setAutoDelete(bool doso) throw();
01049     void requestTermination();
01051     static FXulong id() throw();
01053     FXulong myId() const;
01059     static QThread *current();
01061     static QThread *primaryThread() throw();
01067     QThread *creator() const;
01072     signed char priority() const;
01077     void setPriority(signed char pri);
01079     FXulong processorAffinity() const;
01083     void setProcessorAffinity(FXulong mask=(FXulong)-1, bool recursive=false);
01085     static void sleep(FXuint secs);
01087     static void msleep(FXuint millisecs);
01089     static void yield();
01093     virtual void selfDestruct() { delete this; }
01095     static void exit (void *retcode);
01097     void *result() const throw();
01102     void disableTermination();
01107     bool checkForTerminate();
01112     void enableTermination();
01114     typedef Generic::Functor<Generic::TL::create<void, QThread *>::value> CreationUpcallSpec;
01125     static void addCreationUpcall(CreationUpcallSpec upcallv, bool inThread=false);
01127     static bool removeCreationUpcall(CreationUpcallSpec upcallv);
01135     Generic::BoundFunctorV *addCleanupCall(FXAutoPtr<Generic::BoundFunctorV> handler, bool inThread=false);
01138     bool removeCleanupCall(Generic::BoundFunctorV *handler);
01139 
01140 protected:
01142     virtual void run()=0;
01147     virtual void *cleanup()=0;
01148 public:
01149     static FXDLLLOCAL void *int_cancelWaiterHandle();
01150 private:
01151     friend class QThread_DisableSignals;
01152     static void *int_disableSignals();
01153     static void int_enableSignals(void *oldmask);
01154 };
01155 
01164 class QThread_DTHold : public Generic::DoUndo<QThread, void (QThread::*)(), void (QThread::*)()>
01165 {
01166 public:
01168     QThread_DTHold(QThread *t=QThread::current())
01169         : Generic::DoUndo<QThread, void (QThread::*)(), void (QThread::*)()>(t, &QThread::disableTermination, &QThread::enableTermination) { }
01170 };
01171 
01179 class QThread_DisableSignals
01180 {
01181     void *old_mask;
01182 public:
01184     QThread_DisableSignals() : old_mask(QThread::int_disableSignals()) { }
01185     ~QThread_DisableSignals() { QThread::int_enableSignals(old_mask); }
01186 };
01187 
01227 struct QThreadPoolPrivate;
01228 class FXAPI QThreadPool
01229 {
01230     QThreadPoolPrivate *p;
01231     QThreadPool(const QThreadPool &);
01232     QThreadPool &operator=(const QThreadPool &);
01233     void startThreads(FXuint newno);
01234 public:
01236     typedef void *handle;
01241     QThreadPool(FXuint total=FXProcess::noOfProcessors(), bool dynamic=false);
01242     ~QThreadPool();
01244     FXuint total() const throw();
01246     FXuint maximum() const throw();
01248     FXuint free() const throw();
01253     void setTotal(FXuint newno);
01255     bool dynamic() const throw();
01257     void setDynamic(bool v);
01259     enum DispatchUpcallType
01260     {
01261         PreDispatch=0,          
01262         PostDispatch=1,         
01263         CancelledPreDispatch=2  
01264     };
01266     typedef Generic::Functor<Generic::TL::create<bool, QThreadPool *, handle, DispatchUpcallType>::value> DispatchUpcallSpec;
01269     handle dispatch(FXAutoPtr<Generic::BoundFunctorV> code, FXuint delay=0, DispatchUpcallSpec *upcallv=0);
01271     enum CancelledState
01272     {
01273         NotFound=0,     
01274         Cancelled,      
01275         WasRunning      
01276     };
01279     CancelledState cancel(handle code, bool wait=true);
01282     bool reset(handle code, FXuint delay);
01284     bool wait(handle code, FXuint period=FXINFINITE);
01285 };
01286 
01287 } // namespace
01288 
01289 #ifndef FXBEING_INCLUDED_BY_QTHREAD
01290  #ifdef FXINLINE_MUTEX_IMPLEMENTATION
01291   #define FXBEING_INCLUDED_BY_QTHREAD
01292   #include "int_QMutexImpl.h"
01293   #undef FXBEING_INCLUDED_BY_QTHREAD
01294 
01295   // Also undef stuff from QMutexImpl.h
01296   #undef USE_WINAPI
01297   #undef USE_OURMUTEX
01298   #undef USE_X86
01299   #undef __CLEANUP_C
01300   #undef MUTEX_USESEMA
01301  #endif
01302  #undef QMUTEX_FXAPI
01303  #undef QMUTEX_INLINE
01304  #undef QMUTEX_GLOBALS_FXAPI
01305 #endif
01306 
01307 #endif
01308 

(C) 2002-2009 Niall Douglas. Some parts (C) to assorted authors.
Generated on Fri Nov 20 18:31:26 2009 for TnFOX by doxygen v1.4.7