# 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: 28050 $
    00030  * $Author: rjongbloed $
    00031  * $Date: 2012-07-18 02:15:30 -0500 (Wed, 18 Jul 2012) $
    00032  */
    00033
    00034 #ifndef PTLIB_THREAD_H
    00035 #define PTLIB_THREAD_H
    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
    00051 // PThread
    00052
    00066 class PThread : public PObject
    00067 {
    00068   PCLASSINFO(PThread, PObject);
    00069
    00070   public:
    00073
    00074     enum Priority {
    00075       LowestPriority,
    00076
    00077       LowPriority,
    00078
    00079       NormalPriority,
    00080
    00081       HighPriority,
    00082
    00083       HighestPriority,
    00084
    00085       NumPriorities
    00086     };
    00087
    00089     enum AutoDeleteFlag {
    00091       AutoDeleteThread,
    00092
    00094       NoAutoDeleteThread
    00095     };
    00096
    00119     PThread(
    00120       PINDEX,
    00121       AutoDeleteFlag deletion = AutoDeleteThread,
    00123       Priority priorityLevel = NormalPriority,
    00124       const PString & threadName = PString::Empty()
    00125     );
    00126
    00134     ~PThread();
    00136
    00143     void PrintOn(
    00144       ostream & strm
    00145     ) const;
    00147
    00155     virtual void Restart();
    00156
    00168     virtual void Terminate();
    00169
    00175     virtual PBoolean IsTerminated() const;
    00176
    00179     void WaitForTermination() const;
    00180
    00186     PBoolean WaitForTermination(
    00187       const PTimeInterval & maxWait
    00188     ) const;
    00189
    00202     virtual void Suspend(
    00203       PBoolean susp = true
    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 { return m_threadId; }
    00292     static PThreadIdentifier GetCurrentThreadId();
    00293
    00295     struct Times
    00296     {
    00297       PTimeInterval m_real;
    00298       PTimeInterval m_kernel;
    00299       PTimeInterval m_user;
    00300       friend ostream & operator<<(ostream & strm, const Times & times);
    00301     };
    00302
    00305     bool GetTimes(
    00306       Times & times
    00307     );
    00308
    00316     virtual void Main() = 0;
    00317
    00327     static PThread * Current();
    00328
    00335     static void Yield();
    00336
    00341     static PThread * Create(
    00342       const PNotifier & notifier,
    00343       INT parameter = 0,
    00344       AutoDeleteFlag deletion = AutoDeleteThread,
    00346       Priority priorityLevel = NormalPriority,
    00347       const PString & threadName = PString::Empty(),
    00348       PINDEX stackSize = 65536
    00349     );
    00350     static PThread * Create(
    00351       const PNotifier & notifier,
    00352       const PString & threadName
    00353     ) { return Create(notifier, 0, NoAutoDeleteThread, NormalPriority, threadName); }
    00355
    00356     bool IsAutoDelete() const { return m_autoDelete; }
    00357
    00358   private:
    00359     PThread(bool isProcess);
    00360     // Create a new thread instance as part of a <code>PProcess</code> class.
    00361
    00362     friend class PProcess;
    00363     friend class PExternalThread;
    00364     friend class PHouseKeepingThread;
    00365     // So a PProcess can get at PThread() constructor but nothing else.
    00366
    00367     PThread(const PThread &) : PObject () { }
    00368     // Empty constructor to prevent copying of thread instances.
    00369
    00370     PThread & operator=(const PThread &) { return *this; }
    00371     // Empty assignment operator to prevent copying of thread instances.
    00372
    00373   protected:
    00374     bool   m_isProcess;
    00375     bool   m_autoDelete; // Automatically delete the thread on completion.
    00376     PINDEX m_originalStackSize;
    00377
    00378     PString m_threadName; // Give the thread a name for debugging purposes.
    00379     PMutex  m_threadNameMutex;
    00380
    00381     PThreadIdentifier m_threadId;
    00382
    00383 #if PTRACING
    00384   public:
    00385     struct TraceInfo {
    00386       TraceInfo()
    00387       { traceBlockIndentLevel = 0; }
    00388
    00389       PStack<PStringStream> traceStreams;
    00390       unsigned traceLevel;
    00391       unsigned traceBlockIndentLevel;
    00392     };
    00393
    00394 #ifndef P_HAS_THREADLOCAL_STORAGE
    00395   private:
    00396     friend class PTrace;
    00397     TraceInfo traceInfo;
    00398 #endif // P_HAS_THREADLOCAL_STORAGE
    00399 #endif // PTRACING
    00400
    00401 // Include platform dependent part of class
    00402 #ifdef _WIN32
    00403 #include "msos/ptlib/thread.h"
    00404 #else
    00405 #include "unix/ptlib/thread.h"
    00406 #endif
    00407 };
    00408
    00409 // Include definition of platform dependent thread ID format
    00410 #if defined(_WIN32) && !defined(_WIN32_WCE)
    00411   #define PTHREAD_ID_FMT "%u"
    00412 #else
    00413   #define PTHREAD_ID_FMT "0x%lx"
    00414 #endif
    00415
    00416 #ifdef _MSC_VER
    00417 #pragma warning(disable:4355)
    00418 #endif
    00419
    00424 /*
    00425    This class automates calling a global function with no arguments within it's own thread.
    00426    It is used as follows:
    00427
    00428    void GlobalFunction()
    00429    {
    00430    }
    00431
    00432    ...
    00433    PString arg;
    00434    new PThreadMain(&GlobalFunction)
    00435  */
    00436 class PThreadMain : public PThread
    00437 {
    00438   PCLASSINFO(PThreadMain, PThread);
    00439   public:
    00440     typedef void (*FnType)();
    00441     PThreadMain(FnType function, bool autoDel = false)
    00442       : PThread(10000, autoDel ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread)
    00443       , m_function(function)
    00444       { PThread::Resume(); }
    00445     PThreadMain(const char * file, int line, FnType function, bool autoDel = false)
    00446       : PThread(10000, autoDel ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread,  NormalPriority,
    00447                 psprintf("%s:%08x-%s:%i", GetClass(), (void *)this, file, line))
    00448       , m_function(function)
    00449       { PThread::Resume(); }
    00450     virtual void Main()
    00451       { (*m_function)(); }
    00452
    00453   protected:
    00454     FnType m_function;
    00455 };
    00456
    00457 /*
    00458    This template automates calling a global function with one argument within it's own thread.
    00459    It is used as follows:
    00460
    00461    void GlobalFunction(PString arg)
    00462    {
    00463    }
    00464
    00465    ...
    00466    PString arg;
    00467    new PThread1Arg<PString>(arg, &GlobalFunction)
    00468  */
    00469 template<typename Arg1Type>
    00470 class PThread1Arg : public PThread
    00471 {
    00472   PCLASSINFO(PThread1Arg, PThread);
    00473   public:
    00474     typedef void (*FnType)(Arg1Type arg1);
    00475
    00476     PThread1Arg(Arg1Type arg1, FnType function, bool autoDel = false)
    00477       : PThread(10000, autoDel ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread)
    00478       , m_function(function)
    00479       , m_arg1(arg1)
    00480     { PThread::Resume(); }
    00481     PThread1Arg(const char * file, int line, Arg1Type arg1, FnType function, bool autoDel = false)
    00482       : PThread(10000, autoDel ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread, NormalPriority,
    00483                 psprintf("%s:%08x-%s:%i", GetClass(), (void *)this, file, line))
    00484       , m_function(function)
    00485       , m_arg1(arg1)
    00486       { PThread::Resume(); }
    00487     virtual void Main()
    00488       { (*m_function)(m_arg1); }
    00489
    00490   protected:
    00491     FnType   m_function;
    00492     Arg1Type m_arg1;
    00493 };
    00494
    00495
    00496 /*
    00497    This template automates calling a global function with two arguments within it's own thread.
    00498    It is used as follows:
    00499
    00500    void GlobalFunction(PString arg1, int arg2)
    00501    {
    00502    }
    00503
    00504    ...
    00505    PString arg;
    00506    new PThread2Arg<PString, int>(arg1, arg2, &GlobalFunction)
    00507  */
    00508 template<typename Arg1Type, typename Arg2Type>
    00509 class PThread2Arg : public PThread
    00510 {
    00511   PCLASSINFO(PThread2Arg, PThread);
    00512   public:
    00513     typedef void (*FnType)(Arg1Type arg1, Arg2Type arg2);
    00514     PThread2Arg(Arg1Type arg1, Arg2Type arg2, FnType function, bool autoDel = false)
    00515       : PThread(10000, autoDel ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread)
    00516       , m_function(function)
    00517       , m_arg1(arg1)
    00518       , m_arg2(arg2)
    00519       { PThread::Resume(); }
    00520     PThread2Arg(const char * file, int line, Arg1Type arg1, Arg2Type arg2, FnType function, bool autoDel = false)
    00521       : PThread(10000, autoDel ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread, NormalPriority,
    00522                 psprintf("%s:%08x-%s:%i", GetClass(), (void *)this, file, line))
    00523       , m_function(function)
    00524       , m_arg1(arg1)
    00525       , m_arg2(arg2)
    00526       { PThread::Resume(); }
    00527     virtual void Main()
    00528       { (*m_function)(m_arg1, m_arg2); }
    00529
    00530   protected:
    00531     FnType   m_function;
    00532     Arg1Type m_arg1;
    00533     Arg2Type m_arg2;
    00534 };
    00535
    00536 /*
    00537    This template automates calling a global function with three arguments within it's own thread.
    00538    It is used as follows:
    00539
    00540    void GlobalFunction(PString arg1, int arg2, int arg3)
    00541    {
    00542    }
    00543
    00544    ...
    00545    PString arg;
    00546    new PThread3Arg<PString, int, int>(arg1, arg2, arg3, &GlobalFunction)
    00547  */
    00548 template<typename Arg1Type, typename Arg2Type, typename Arg3Type>
    00549 class PThread3Arg : public PThread
    00550 {
    00551   PCLASSINFO(PThread3Arg, PThread);
    00552   public:
    00553     typedef void (*FnType)(Arg1Type arg1, Arg2Type arg2, Arg3Type arg3);
    00554     PThread3Arg(Arg1Type arg1, Arg2Type arg2, Arg3Type arg3, FnType function, bool autoDel = false)
    00555       : PThread(10000, autoDel ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread)
    00556       , m_function(function)
    00557       , m_arg1(arg1)
    00558       , m_arg2(arg2)
    00559       , m_arg3(arg3)
    00560       { PThread::Resume(); }
    00561     PThread3Arg(const char * file, int line, Arg1Type arg1, Arg2Type arg2, Arg3Type arg3, FnType function, bool autoDel = false)
    00562       : PThread(10000, autoDel ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread, NormalPriority,
    00563                 psprintf("%s:%08x-%s:%i", GetClass(), (void *)this, file, line))
    00564       , m_function(function)
    00565       , m_arg1(arg1)
    00566       , m_arg2(arg2)
    00567       , m_arg3(arg3)
    00568       { PThread::Resume(); }
    00569     virtual void Main()
    00570       { (*m_function)(m_arg1, m_arg2, m_arg3); }
    00571
    00572   protected:
    00573     FnType   m_function;
    00574     Arg1Type m_arg1;
    00575     Arg2Type m_arg2;
    00576     Arg2Type m_arg3;
    00577 };
    00578
    00579 /*
    00580    This template automates calling a member function with no arguments within it's own thread.
    00581    It is used as follows:
    00582
    00583    class Example {
    00584      public:
    00585       void Function()
    00586       {
    00587       }
    00588    };
    00589
    00590    ...
    00591    Example ex;
    00592    new PThreadObj<Example>(ex, &Example::Function)
    00593  */
    00594
    00595 template <typename ObjType>
    00596 class PThreadObj : public PThread
    00597 {
    00598     PCLASSINFO(PThreadObj, PThread);
    00599   public:
    00600     typedef void (ObjType::*ObjTypeFn)();
    00601
    00602     PThreadObj(
    00603       ObjType & obj,
    00604       ObjTypeFn function,
    00605       bool autoDel = false,
    00606       const char * name = NULL,
    00607       PThread::Priority priority = PThread::NormalPriority
    00608     ) : PThread(10000,
    00609                 autoDel ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread,
    00610                 priority,
    00611                 name)
    00612       , m_object(obj)
    00613       , m_function(function)
    00614     {
    00615       PThread::Resume();
    00616     }
    00617
    00618     void Main()
    00619     {
    00620       (m_object.*m_function)();
    00621     }
    00622
    00623   protected:
    00624     ObjType & m_object;
    00625     ObjTypeFn m_function;
    00626 };
    00627
    00628
    00629 /*
    00630    This template automates calling a member function with one argument within it's own thread.
    00631    It is used as follows:
    00632
    00633    class Example {
    00634      public:
    00635       void Function(PString arg)
    00636       {
    00637       }
    00638    };
    00639
    00640    ...
    00641    Example ex;
    00642    PString str;
    00643    new PThreadObj1Arg<Example>(ex, str, &Example::Function)
    00644  */
    00645 template <class ObjType, typename Arg1Type>
    00646 class PThreadObj1Arg : public PThread
    00647 {
    00648     PCLASSINFO(PThreadObj1Arg, PThread);
    00649   public:
    00650     typedef void (ObjType::*ObjTypeFn)(Arg1Type);
    00651
    00652     PThreadObj1Arg(
    00653       ObjType & obj,
    00654       Arg1Type arg1,
    00655       ObjTypeFn function,
    00656       bool autoDel = false,
    00657       const char * name = NULL,
    00658       PThread::Priority priority = PThread::NormalPriority
    00659     ) : PThread(10000,
    00660                 autoDel ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread,
    00661                 priority,
    00662                 name)
    00663       , m_object(obj)
    00664       , m_function(function)
    00665       , m_arg1(arg1)
    00666     {
    00667       PThread::Resume();
    00668     }
    00669
    00670     void Main()
    00671     {
    00672       (m_object.*m_function)(m_arg1);
    00673     }
    00674
    00675   protected:
    00676     ObjType & m_object;
    00677     ObjTypeFn m_function;
    00678     Arg1Type  m_arg1;
    00679 };
    00680
    00681 template <class ObjType, typename Arg1Type, typename Arg2Type>
    00682 class PThreadObj2Arg : public PThread
    00683 {
    00684     PCLASSINFO(PThreadObj2Arg, PThread);
    00685   public:
    00686     typedef void (ObjType::*ObjTypeFn)(Arg1Type, Arg2Type);
    00687
    00688     PThreadObj2Arg(
    00689       ObjType & obj,
    00690       Arg1Type arg1,
    00691       Arg2Type arg2,
    00692       ObjTypeFn function,
    00693       bool autoDel = false,
    00694       const char * name = NULL,
    00695       PThread::Priority priority = PThread::NormalPriority
    00696     ) : PThread(10000,
    00697                 autoDel ? PThread::AutoDeleteThread : PThread::NoAutoDeleteThread,
    00698                 priority,
    00699                 name)
    00700       , m_object(obj)
    00701       , m_function(function)
    00702       , m_arg1(arg1)
    00703       , m_arg2(arg2)
    00704     {
    00705       PThread::Resume();
    00706     }
    00707
    00708     void Main()
    00709     {
    00710       (m_object.*m_function)(m_arg1, m_arg2);
    00711     }
    00712
    00713   protected:
    00714     ObjType & m_object;
    00715     ObjTypeFn m_function;
    00716     Arg1Type  m_arg1;
    00717     Arg2Type  m_arg2;
    00718 };
    00719
    00720
    00722 //
    00723 // PThreadLocalStorage
    00724 //
    00725
    00726 #ifdef _WIN32
    00727
    00728 #define P_HAS_THREADLOCAL_STORAGE 1
    00729
    00730 template <class Storage_T>
    00731 class PThreadLocalStorage
    00732 {
    00733   public:
    00734     typedef DWORD Key_T;
    00735     typedef Storage_T value_type;
    00736
    00737     PThreadLocalStorage()
    00738     { key = TlsAlloc(); }
    00739
    00740     ~PThreadLocalStorage()
    00741     { TlsFree(key);  }
    00742
    00743     Key_T GetKey() const
    00744     { return key; }
    00745
    00746     value_type * Get()
    00747     { return (value_type *) TlsGetValue(key); }
    00748
    00749     void Set(value_type * v)
    00750     { TlsSetValue(key, (LPVOID)v); }
    00751
    00752   protected:
    00753     DWORD key;
    00754 };
    00755
    00756 #elif defined(P_PTHREADS)
    00757
    00758 #include <pthread.h>
    00759
    00760 #define P_HAS_THREADLOCAL_STORAGE 1
    00761
    00762 template <class Storage_T>
    00763 class PThreadLocalStorage
    00764 {
    00765   public:
    00766     typedef pthread_key_t Key_T;
    00767     typedef Storage_T value_type;
    00768
    00769     PThreadLocalStorage()
    00770     { pthread_key_create(&key, NULL); }
    00771
    00772     ~PThreadLocalStorage()
    00773     { pthread_key_delete(key); }
    00774
    00775     Key_T GetKey() const
    00776     { return key; }
    00777
    00778     value_type * Get()
    00779     { return (value_type *)pthread_getspecific(key); }
    00780
    00781     void Set(value_type * v)
    00782     { pthread_setspecific(key, v); }
    00783
    00784   private:
    00785     Key_T key;
    00786 };
    00787
    00788 #else
    00789
    00790 #undef P_HAS_THREADLOCAL_STORAGE 1
    00791 #warning("Thread local storage not supported");
    00792
    00793 #endif
    00794
    00795
    00796 #ifdef _MSC_VER
    00797 #pragma warning(default:4355)
    00798 #endif
    00799
    00800 #endif // PTLIB_THREAD_H
    00801
    00802 // End Of File ///////////////////////////////////////////////////////////////