thread.h

Go to the documentation of this file.
00001 /*
00002  * thread.h
00003  *
00004  * Executable thread encapsulation class (pre-emptive if OS allows).
00005  *
00006  * Portable Tools Library
00007  *
00008  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
00009  *
00010  * The contents of this file are subject to the Mozilla Public License
00011  * Version 1.0 (the "License"); you may not use this file except in
00012  * compliance with the License. You may obtain a copy of the License at
00013  * http://www.mozilla.org/MPL/
00014  *
00015  * Software distributed under the License is distributed on an "AS IS"
00016  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
00017  * the License for the specific language governing rights and limitations
00018  * under the License.
00019  *
00020  * The Original Code is Portable Windows Library.
00021  *
00022  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
00023  *
00024  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
00025  * All Rights Reserved.
00026  *
00027  * Contributor(s): ______________________________________.
00028  *
00029  * $Revision: 20492 $
00030  * $Author: rjongbloed $
00031  * $Date: 2008-06-24 23:36:32 +0000 (Tue, 24 Jun 2008) $
00032  */
00033 
00034 #ifndef _PTHREAD
00035 #define _PTHREAD
00036 
00037 #ifdef P_USE_PRAGMA
00038 #pragma interface
00039 #endif
00040 
00041 #ifdef Priority
00042 #undef Priority
00043 #endif
00044 
00045 #include <ptlib/mutex.h>
00046 
00047 class PSemaphore;
00048 
00049 #define PThreadIdentifer PThreadIdentifier
00050 
00051 typedef P_THREADIDENTIFIER PThreadIdentifier;
00052 
00054 // PThread
00055 
00069 class PThread : public PObject
00070 {
00071   PCLASSINFO(PThread, PObject);
00072 
00073   public:
00076 
00077     enum Priority {
00078       LowestPriority,  
00079 
00080       LowPriority,     
00081 
00082       NormalPriority,  
00083 
00084       HighPriority,    
00085 
00086       HighestPriority, 
00087 
00088       NumPriorities
00089     };
00090 
00092     enum AutoDeleteFlag {
00094       AutoDeleteThread,   
00095 
00097       NoAutoDeleteThread  
00098     };
00099 
00122     PThread(
00123       PINDEX,                 
00124       AutoDeleteFlag deletion = AutoDeleteThread,
00126       Priority priorityLevel = NormalPriority,  
00127       const PString & threadName = PString::Empty() 
00128     );
00129 
00137     ~PThread();
00139 
00146     void PrintOn(
00147       ostream & strm    
00148     ) const;
00150 
00158     virtual void Restart();
00159 
00171     virtual void Terminate();
00172 
00178     virtual PBoolean IsTerminated() const;
00179 
00185     void WaitForTermination() const;
00186     PBoolean WaitForTermination(
00187       const PTimeInterval & maxWait  
00188     ) const;
00189 
00202     virtual void Suspend(
00203       PBoolean susp = PTrue    
00204     );
00205 
00225     virtual void Resume();
00226 
00234     virtual PBoolean IsSuspended() const;
00235 
00237     static void Sleep(
00238       const PTimeInterval & delay   
00239     );
00240 
00244     virtual void SetPriority(
00245       Priority priorityLevel    
00246     );
00247 
00253     virtual Priority GetPriority() const;
00254 
00258     virtual void SetAutoDelete(
00259       AutoDeleteFlag deletion = AutoDeleteThread  
00260     );
00261 
00265     void SetNoAutoDelete() { SetAutoDelete(NoAutoDeleteThread); }
00266 
00272     virtual PString GetThreadName() const;
00273 
00279     virtual void SetThreadName(
00280       const PString & name        
00281     );
00283 
00291     virtual PThreadIdentifier GetThreadId() const;
00292     static PThreadIdentifier GetCurrentThreadId();
00293 
00301     virtual void Main() = 0;
00302 
00312     static PThread * Current();
00313 
00320     static void Yield();
00321 
00326     static PThread * Create(
00327       const PNotifier & notifier,     
00328       INT parameter = 0,              
00329       AutoDeleteFlag deletion = AutoDeleteThread,
00331       Priority priorityLevel = NormalPriority,  
00332       const PString & threadName = PString::Empty(), 
00333       PINDEX stackSize = 65536         
00334     );
00335     static PThread * Create(
00336       const PNotifier & notifier,     
00337       const PString & threadName      
00338     ) { return Create(notifier, 0, NoAutoDeleteThread, NormalPriority, threadName); }
00340 
00341   protected:
00342     void InitialiseProcessThread();
00343     /* Initialialise the primordial thread, the one in the PProcess. This is
00344        required due to the bootstrap logic of processes and threads.
00345      */
00346 
00347   private:
00348     PThread();
00349     // Create a new thread instance as part of a #PProcess class.
00350 
00351     friend class PProcess;
00352     // So a PProcess can get at PThread() constructor but nothing else.
00353 
00354     PThread(const PThread &) : PObject () { }
00355     // Empty constructor to prevent copying of thread instances.
00356 
00357     PThread & operator=(const PThread &) { return *this; }
00358     // Empty assignment operator to prevent copying of thread instances.
00359 
00360     PBoolean autoDelete;
00361     // Automatically delete the thread on completion.
00362 
00363     // Give the thread a name for debugging purposes.
00364     PString threadName;
00365     PMutex threadNameMutex;
00366 
00367 #if PTRACING
00368   public:
00369     struct TraceInfo {
00370       TraceInfo()
00371       { traceBlockIndentLevel = 0; }
00372 
00373       PStack<PStringStream> traceStreams;
00374       unsigned traceLevel;
00375       unsigned traceBlockIndentLevel;
00376     };
00377 
00378 #ifndef P_HAS_THREADLOCAL_STORAGE
00379   private:
00380     friend class PTrace;
00381     TraceInfo traceInfo;
00382 #endif // P_HAS_THREADLOCAL_STORAGE
00383 #endif // PTRACING
00384 
00385 // Include platform dependent part of class
00386 #ifdef _WIN32
00387 #include "msos/ptlib/thread.h"
00388 #else
00389 #include "unix/ptlib/thread.h"
00390 #endif
00391 };
00392 
00393 // Include definition of platform dependent thread ID format
00394 #if defined(_WIN32) && !defined(_WIN32_WCE)
00395   #define PTHREAD_ID_FMT ":%u"
00396 #else
00397   #define PTHREAD_ID_FMT ":0x%x"
00398 #endif
00399 
00400 #ifdef _MSC_VER
00401 #pragma warning(disable:4355)
00402 #endif
00403 
00408 /*
00409    This class automates calling a global function with no arguments within it's own thread.
00410    It is used as follows:
00411 
00412    void GlobalFunction()
00413    {
00414    }
00415 
00416    ...
00417    PString arg;
00418    new PThreadMain(&GlobalFunction)
00419  */
00420 class PThreadMain : public PThread
00421 {
00422   PCLASSINFO(PThreadMain, PThread);
00423   public:
00424     typedef void (*FnType)(); 
00425     PThreadMain(FnType _fn, PBoolean _autoDelete = PFalse)
00426       : PThread(10000, _autoDelete ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread), fn(_fn)
00427     { PThread::Resume(); }
00428     PThreadMain(const char * _file, int _line, FnType _fn, PBoolean _autoDelete = PFalse)
00429       : PThread(10000, _autoDelete ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread,  NormalPriority,
00430         psprintf("%s:%08x-%s:%i", GetClass(), (void *)this, _file, _line)), fn(_fn)
00431     { PThread::Resume(); }
00432     virtual void Main()
00433     { (*fn)(); }
00434     FnType fn;
00435 };
00436 
00437 /*
00438    This template automates calling a global function with one argument within it's own thread.
00439    It is used as follows:
00440 
00441    void GlobalFunction(PString arg)
00442    {
00443    }
00444 
00445    ...
00446    PString arg;
00447    new PThread1Arg<PString>(arg, &GlobalFunction)
00448  */
00449 template<typename Arg1Type>
00450 class PThread1Arg : public PThread
00451 {
00452   PCLASSINFO(PThread1Arg, PThread);
00453   public:
00454     typedef void (*FnType)(Arg1Type arg1); 
00455     PThread1Arg(Arg1Type _arg1, FnType _fn, PBoolean _autoDelete = PFalse)
00456       : PThread(10000, _autoDelete ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread), fn(_fn),
00457         arg1(_arg1)
00458     { PThread::Resume(); }
00459     PThread1Arg(const char * _file, int _line, Arg1Type _arg1, FnType _fn, PBoolean _autoDelete = PFalse)
00460       : PThread(10000, _autoDelete ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread,  NormalPriority,
00461         psprintf("%s:%08x-%s:%i", GetClass(), (void *)this, _file, _line)), fn(_fn),
00462         arg1(_arg1)
00463     { PThread::Resume(); }
00464     virtual void Main()
00465     { (*fn)(arg1); }
00466     FnType fn;
00467     Arg1Type arg1;
00468 };
00469 
00470 
00471 /*
00472    This template automates calling a global function with two arguments within it's own thread.
00473    It is used as follows:
00474 
00475    void GlobalFunction(PString arg1, int arg2)
00476    {
00477    }
00478 
00479    ...
00480    PString arg;
00481    new PThread2Arg<PString, int>(arg1, arg2, &GlobalFunction)
00482  */
00483 template<typename Arg1Type, typename Arg2Type>
00484 class PThread2Arg : public PThread
00485 {
00486   PCLASSINFO(PThread2Arg, PThread);
00487   public:
00488     typedef void (*FnType)(Arg1Type arg1, Arg2Type arg2); 
00489     PThread2Arg(Arg1Type _arg1, Arg2Type _arg2, FnType _fn, PBoolean _autoDelete = PFalse)
00490       : PThread(10000, _autoDelete ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread), fn(_fn),
00491         arg1(_arg1), arg2(_arg2)
00492     { PThread::Resume(); }
00493     PThread2Arg(const char * _file, int _line, Arg1Type _arg1, Arg2Type _arg2, FnType _fn, PBoolean _autoDelete = PFalse)
00494       : PThread(10000, _autoDelete ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread, NormalPriority,
00495         psprintf("%s:%08x-%s:%i", GetClass(), (void *)this, _file, _line)), fn(_fn),
00496         arg1(_arg1), arg2(_arg2)
00497     { PThread::Resume(); }
00498     virtual void Main()
00499     { (*fn)(arg1, arg2); }
00500     FnType fn;
00501     Arg1Type arg1;
00502     Arg2Type arg2;
00503 };
00504 
00505 /*
00506    This template automates calling a global function with three arguments within it's own thread.
00507    It is used as follows:
00508 
00509    void GlobalFunction(PString arg1, int arg2, int arg3)
00510    {
00511    }
00512 
00513    ...
00514    PString arg;
00515    new PThread3Arg<PString, int, int>(arg1, arg2, arg3, &GlobalFunction)
00516  */
00517 template<typename Arg1Type, typename Arg2Type, typename Arg3Type>
00518 class PThread3Arg : public PThread
00519 {
00520   PCLASSINFO(PThread3Arg, PThread);
00521   public:
00522     typedef void (*FnType)(Arg1Type arg1, Arg2Type arg2, Arg3Type arg3); 
00523     PThread3Arg(Arg1Type _arg1, Arg2Type _arg2, Arg3Type _arg3, FnType _fn, PBoolean _autoDelete = PFalse)
00524       : PThread(10000, _autoDelete ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread), fn(_fn),
00525         arg1(_arg1), arg2(_arg2), arg3(_arg3)
00526     { PThread::Resume(); }
00527     PThread3Arg(const char * _file, int _line, Arg1Type _arg1, Arg2Type _arg2, Arg3Type _arg3, FnType _fn, PBoolean _autoDelete = PFalse)
00528       : PThread(10000, _autoDelete ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread, NormalPriority,
00529         psprintf("%s:%08x-%s:%i", GetClass(), (void *)this, _file, _line)), fn(_fn),
00530         arg1(_arg1), arg2(_arg2), arg3(_arg3)
00531     { PThread::Resume(); }
00532     virtual void Main()
00533     { (*fn)(arg1, arg2, arg3); }
00534     FnType fn;
00535     Arg1Type arg1;
00536     Arg2Type arg2;
00537     Arg2Type arg3;
00538 };
00539 
00540 /*
00541    This template automates calling a member function with no arguments within it's own thread.
00542    It is used as follows:
00543 
00544    class Example {
00545      public:
00546       void Function()
00547       {
00548       }
00549    };
00550 
00551    ...
00552    Example ex;
00553    new PThreadObj<Example>(ex, &Example::Function)
00554  */
00555 
00556 template <typename ObjType>
00557 class PThreadObj : public PThread
00558 {
00559   public:
00560   PCLASSINFO(PThreadObj, PThread);
00561   public:
00562     typedef void (ObjType::*ObjTypeFn)(); 
00563     PThreadObj(ObjType & _obj, ObjTypeFn _fn, PBoolean _autoDelete = PFalse)
00564       : PThread(10000, _autoDelete ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread),
00565         obj(_obj), fn(_fn)
00566     { PThread::Resume(); }
00567     PThreadObj(const char * _file, int _line, ObjType & _obj, ObjTypeFn _fn, PBoolean _autoDelete = PFalse)
00568       : PThread(10000, _autoDelete ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread, NormalPriority,
00569         psprintf("%s:%08x-%s:%i", GetClass(), (void *)this, _file, _line)),
00570         obj(_obj), fn(_fn)
00571     { PThread::Resume(); }
00572     void Main()
00573     { (obj.*fn)(); }
00574 
00575   protected:
00576     ObjType & obj;
00577     ObjTypeFn fn;
00578 };
00579 
00580 
00581 /*
00582    This template automates calling a member function with one argument within it's own thread.
00583    It is used as follows:
00584 
00585    class Example {
00586      public:
00587       void Function(PString arg)
00588       {
00589       }
00590    };
00591 
00592    ...
00593    Example ex;
00594    PString str;
00595    new PThreadObj1Arg<Example>(ex, str, &Example::Function)
00596  */
00597 template <class ObjType, typename Arg1Type>
00598 class PThreadObj1Arg : public PThread
00599 {
00600   PCLASSINFO(PThreadObj1Arg, PThread);
00601   public:
00602     typedef void (ObjType::*ObjTypeFn)(Arg1Type); 
00603     PThreadObj1Arg(ObjType & _obj, Arg1Type _arg1, ObjTypeFn _fn, PBoolean _autoDelete = PFalse)
00604       : PThread(10000, _autoDelete ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread),
00605                                 obj(_obj), fn(_fn), arg1(_arg1)
00606     { PThread::Resume(); }
00607     PThreadObj1Arg(const char * _file, int _line, ObjType & _obj, Arg1Type _arg1, ObjTypeFn _fn, PBoolean _autoDelete = PFalse)
00608       : PThread(10000, _autoDelete ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread, NormalPriority,
00609                                 psprintf("%s:%08x-%s:%i", GetClass(), (void *)this, _file, _line)),
00610                                 obj(_obj), fn(_fn), arg1(_arg1)
00611     { PThread::Resume(); }
00612     void Main()
00613     { (obj.*fn)(arg1); }
00614 
00615   protected:
00616     ObjType & obj;
00617     ObjTypeFn fn;
00618     Arg1Type arg1;
00619 };
00620 
00621 template <class ObjType, typename Arg1Type, typename Arg2Type>
00622 class PThreadObj2Arg : public PThread
00623 {
00624   PCLASSINFO(PThreadObj2Arg, PThread);
00625   public:
00626     typedef void (ObjType::*ObjTypeFn)(Arg1Type, Arg2Type); 
00627     PThreadObj2Arg(ObjType & _obj, Arg1Type _arg1, Arg2Type _arg2, ObjTypeFn _fn, PBoolean _autoDelete = PFalse)
00628       : PThread(10000, _autoDelete ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread),
00629                                 obj(_obj), fn(_fn), arg1(_arg1), arg2(_arg2)
00630     { PThread::Resume(); }
00631     PThreadObj2Arg(const char * _file, int _line, ObjType & _obj, Arg1Type _arg1, Arg2Type _arg2, ObjTypeFn _fn, PBoolean _autoDelete = PFalse)
00632       : PThread(10000, _autoDelete ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread, NormalPriority,
00633                                 psprintf("%s:%08x-%s:%i", GetClass(), (void *)this, _file, _line)),
00634                                 obj(_obj), fn(_fn), arg1(_arg1), arg2(_arg2)
00635     { PThread::Resume(); }
00636     void Main()
00637     { (obj.*fn)(arg1, arg2); }
00638 
00639   protected:
00640     ObjType & obj;
00641     ObjTypeFn fn;
00642     Arg1Type arg1;
00643     Arg1Type arg2;
00644 };
00645 
00646 
00648 //
00649 // PThreadLocalStorage
00650 //
00651 
00652 #ifdef _WIN32
00653 
00654 #define P_HAS_THREADLOCAL_STORAGE 1
00655 
00656 template <class Storage_T>
00657 class PThreadLocalStorage
00658 {
00659   public:
00660     typedef DWORD Key_T;
00661     typedef Storage_T value_type;
00662 
00663     PThreadLocalStorage()
00664     { key = TlsAlloc(); }
00665 
00666     ~PThreadLocalStorage()
00667     { TlsFree(key);  }
00668 
00669     Key_T GetKey() const
00670     { return key; }
00671 
00672     value_type * Get()
00673     { return (value_type *) TlsGetValue(key); }
00674 
00675     void Set(value_type * v)
00676     { TlsSetValue(key, (LPVOID)v); }
00677 
00678   protected:
00679     DWORD key;
00680 };
00681 
00682 #elif defined(P_PTHREADS)
00683 
00684 #include <pthread.h>
00685 
00686 #define P_HAS_THREADLOCAL_STORAGE 1
00687 
00688 template <class Storage_T>
00689 class PThreadLocalStorage
00690 {
00691   public:
00692     typedef pthread_key_t Key_T;
00693     typedef Storage_T value_type;
00694 
00695     PThreadLocalStorage()
00696     { pthread_key_create(&key, NULL); }
00697 
00698     ~PThreadLocalStorage()
00699     { pthread_key_delete(key); }
00700 
00701     Key_T GetKey() const
00702     { return key; }
00703 
00704     value_type * Get()
00705     { return (value_type *)pthread_getspecific(key); }
00706 
00707     void Set(value_type * v)
00708     { pthread_setspecific(key, v); }
00709 
00710   private:
00711     Key_T key;
00712 };
00713 
00714 #else
00715 
00716 #undef P_HAS_THREADLOCAL_STORAGE 1
00717 #warning("Thread local storage not supported");
00718 
00719 #endif
00720 
00721 
00722 #ifdef _MSC_VER
00723 #pragma warning(default:4355)
00724 #endif
00725 
00726 #endif // _PTHREAD
00727 
00728 // End Of File ///////////////////////////////////////////////////////////////

Generated on Mon Sep 15 01:21:35 2008 for PTLib by  doxygen 1.5.1