PTLib
Version 2.10.4
|
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: 24177 $ 00030 * $Author: rjongbloed $ 00031 * $Date: 2010-04-05 06:52:04 -0500 (Mon, 05 Apr 2010) $ 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 #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 00182 void WaitForTermination() const; 00183 00189 PBoolean WaitForTermination( 00190 const PTimeInterval & maxWait 00191 ) const; 00192 00205 virtual void Suspend( 00206 PBoolean susp = true 00207 ); 00208 00228 virtual void Resume(); 00229 00237 virtual PBoolean IsSuspended() const; 00238 00240 static void Sleep( 00241 const PTimeInterval & delay 00242 ); 00243 00247 virtual void SetPriority( 00248 Priority priorityLevel 00249 ); 00250 00256 virtual Priority GetPriority() const; 00257 00261 virtual void SetAutoDelete( 00262 AutoDeleteFlag deletion = AutoDeleteThread 00263 ); 00264 00268 void SetNoAutoDelete() { SetAutoDelete(NoAutoDeleteThread); } 00269 00275 virtual PString GetThreadName() const; 00276 00282 virtual void SetThreadName( 00283 const PString & name 00284 ); 00286 00294 virtual PThreadIdentifier GetThreadId() const; 00295 static PThreadIdentifier GetCurrentThreadId(); 00296 00298 struct Times 00299 { 00300 PTimeInterval m_real; 00301 PTimeInterval m_kernel; 00302 PTimeInterval m_user; 00303 friend ostream & operator<<(ostream & strm, const Times & times); 00304 }; 00305 00308 bool GetTimes( 00309 Times & times 00310 ); 00311 00319 virtual void Main() = 0; 00320 00330 static PThread * Current(); 00331 00338 static void Yield(); 00339 00344 static PThread * Create( 00345 const PNotifier & notifier, 00346 INT parameter = 0, 00347 AutoDeleteFlag deletion = AutoDeleteThread, 00349 Priority priorityLevel = NormalPriority, 00350 const PString & threadName = PString::Empty(), 00351 PINDEX stackSize = 65536 00352 ); 00353 static PThread * Create( 00354 const PNotifier & notifier, 00355 const PString & threadName 00356 ) { return Create(notifier, 0, NoAutoDeleteThread, NormalPriority, threadName); } 00358 00359 bool IsAutoDelete() const { return autoDelete; } 00360 00361 private: 00362 PThread(); 00363 // Create a new thread instance as part of a <code>PProcess</code> class. 00364 00365 friend class PProcess; 00366 friend class PExternalThread; 00367 friend class PHouseKeepingThread; 00368 // So a PProcess can get at PThread() constructor but nothing else. 00369 00370 PThread(const PThread &) : PObject () { } 00371 // Empty constructor to prevent copying of thread instances. 00372 00373 PThread & operator=(const PThread &) { return *this; } 00374 // Empty assignment operator to prevent copying of thread instances. 00375 00376 PBoolean autoDelete; 00377 // Automatically delete the thread on completion. 00378 00379 // Give the thread a name for debugging purposes. 00380 PString threadName; 00381 PMutex threadNameMutex; 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%x" 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 ///////////////////////////////////////////////////////////////