home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / CLASSINC.PAK / THREAD.H < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  35.0 KB  |  1,258 lines

  1. //----------------------------------------------------------------------------
  2. // Borland Class Library
  3. // Copyright (c) 1993, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   5.13  $
  6. //
  7. // Defines the class TSemaphore and its nested class TLock.
  8. // Defines the derived semaphore class TMutex
  9. // Defines the derived semaphore class TCountedSemaphore
  10. // Defines the derived semaphore class TEventSemaphore
  11. // Defined the semaphore set class TSemaphoreSet and its nested class TLock.
  12. //
  13. // Defines the class TCriticalSection and its nested class TLock.
  14. //
  15. // Defines the class TSync and its nested class TLock.
  16. // Defines the template TStaticSync and its nested class TLock.
  17. //
  18. // Defines the class TThread.
  19. //----------------------------------------------------------------------------
  20. #if !defined(CLASSLIB_THREAD_H)
  21. #define CLASSLIB_THREAD_H
  22.  
  23. #if !defined(CLASSLIB_DEFS_H)
  24. # include <classlib/defs.h>
  25. #endif
  26. #if !defined(BI_MULTI_THREAD)
  27. # error Thread classes require multi-threaded operating system.
  28. #endif
  29.  
  30. #if !defined(SERVICES_WSYSINC_H)
  31. # include <services/wsysinc.h>
  32. #endif
  33. #if !defined(SERVICES_CHECKS_H)
  34. # include <services/checks.h>
  35. #endif
  36. #if !defined(SERVICES_CSTRING_H)
  37. # include <services/cstring.h>
  38. #endif
  39.  
  40. #if defined(BI_CLASSLIB_NO_po)
  41. # pragma option -po-
  42. #endif
  43.  
  44. #if defined(BI_NAMESPACE)
  45. namespace ClassLib {
  46. #endif
  47.  
  48. //
  49. // class TSemaphore
  50. // ~~~~~ ~~~~~~~~~~
  51. // Base class for handle-based thread synchronization classes, TMutex,
  52. // TCountedSemaphore and TEventSemaphore. Defines some types & constants, as
  53. // well as holding the system object handle for Win32.
  54. //
  55. class _BIDSCLASS TSemaphore
  56. {
  57.   public:
  58. #if defined(BI_PLAT_WIN32)
  59.    ~TSemaphore();
  60.  
  61.     enum { NoWait = 0, NoLimit = INFINITE };
  62.     typedef HANDLE THandle;
  63.     operator THandle() const;
  64.  
  65. #elif defined(BI_PLAT_OS2)
  66.     virtual ~TSemaphore();
  67.     enum { NoWait = SEM_IMMEDIATE_RETURN, NoLimit = SEM_INDEFINITE_WAIT };
  68. #endif
  69.  
  70.     class TLock {
  71.       public:
  72.         TLock(const TSemaphore&, ulong timeOut = NoLimit, bool alertable = false);
  73.        ~TLock();
  74.  
  75.         bool WasAquired() const;  // See if really aquired, or just timed-out
  76.  
  77.         // Release lock early & relinquish, i.e. before destructor. Or, just
  78.         // drop the lock count on an exiting semaphore & keep locked 'til dtor
  79.         //
  80.         void Release(bool relinquish = false);
  81.  
  82.       private:
  83.         const TSemaphore* Sem;
  84.     };
  85.     friend class TLock;
  86.     friend class _BIDSCLASS TSemaphoreSet;
  87.  
  88.   protected:
  89. #if defined(BI_PLAT_OS2)
  90.     virtual void Aquire() = 0;   // Derived class must provide aquire
  91. #endif
  92.     virtual void Release() = 0;  // Derived class must provide release
  93.  
  94. #if defined(BI_PLAT_WIN32)
  95.     THandle Handle;              // Derived class must initialize
  96. #endif
  97. };
  98.  
  99. //
  100. // class TMutex
  101. // ~~~~~ ~~~~~~
  102. // Mutual-exclusive semaphore
  103. //
  104. // TMutex provides a system-independent interface to critical sections in
  105. // threads. With suitable underlying implementations the same code can be used
  106. // under OS/2 and Windows NT.
  107. //
  108. // An object of type TMutex can be used in conjunction with objects of type
  109. // TMutex::TLock (inherited from TSemaphore) to guarantee that only one thread
  110. // can be executing any of the code sections protected by the lock at any
  111. // given time.
  112. //
  113. // The differences between the classes TCriticalSection and TMutex are that a
  114. // timeout can be specified when creating a Lock on a TMutex object, and that
  115. // a TMutex object has a HANDLE which can be used outside the class. This
  116. // mirrors the distinction made in Windows NT between a CRITICALSECTION and a
  117. // Mutex. Under NT a TCriticalSection object is much faster than a TMutex
  118. // object. Under operating systems that don't make this distinction a
  119. // TCriticalSection object can use the same underlying implementation as a
  120. // TMutex, losing the speed advantage that it has under NT.
  121. //
  122. class _BIDSCLASS TMutex : public TSemaphore
  123. {
  124.   public:
  125. #if defined(BI_PLAT_WIN32)
  126.     TMutex(const _TCHAR* name = 0, LPSECURITY_ATTRIBUTES sa = 0);
  127.     TMutex(const _TCHAR* name, bool inherit, uint32 access = MUTEX_ALL_ACCESS);
  128.     TMutex(THandle handle);
  129. #elif defined(BI_PLAT_OS2)
  130.     TMutex(const _TCHAR* name = 0);
  131.    ~TMutex();
  132. #endif
  133.  
  134. #if defined(BI_PLAT_OS2)
  135.     typedef HMTX THandle;
  136.     operator THandle() const;
  137. #endif
  138.     typedef TLock Lock;  // For compatibility with old T-less typename
  139.  
  140.     // If another mutex with the same name existed when this mutex
  141.     // was created, then another handle to the object exists and
  142.     // someone else may be using it too.
  143.     //
  144. #if defined(BI_PLAT_WIN32)
  145.     bool IsShared();
  146. #endif
  147.  
  148.   private:
  149.     TMutex(const TMutex&);
  150.     const TMutex& operator =(const TMutex&);
  151.  
  152.     virtual void Release();  // Release this mutex semaphore
  153.  
  154. #if defined(BI_PLAT_WIN32)
  155.     bool Shared;
  156. #endif
  157.  
  158. #if defined(BI_PLAT_OS2)
  159.     THandle Handle;
  160. #endif
  161. };
  162.  
  163. #if defined(BI_PLAT_WIN32)
  164. //
  165. // class TCountedSemaphore
  166. // ~~~~~ ~~~~~~~~~~~~~~~~~
  167. // Counted semaphore. Currently Win32 only
  168. //
  169. class _BIDSCLASS TCountedSemaphore : public TSemaphore
  170. {
  171.   public:
  172.     TCountedSemaphore(int initialCount, int maxCount, const _TCHAR* name = 0,
  173.                       LPSECURITY_ATTRIBUTES sa = 0);
  174.     TCountedSemaphore(const _TCHAR* name, bool inherit,
  175.                       uint32 access = SEMAPHORE_ALL_ACCESS);
  176.     TCountedSemaphore(THandle handle);
  177.  
  178.   private:
  179.     TCountedSemaphore(const TCountedSemaphore&);
  180.     const TCountedSemaphore& operator =(const TCountedSemaphore&);
  181.  
  182.     virtual void Release();  // Release this counted semaphore
  183. };
  184. #endif
  185.  
  186. //
  187. // class TEventSemaphore
  188. // ~~~~~ ~~~~~~~~~~~~~~~
  189. //
  190. class _BIDSCLASS TEventSemaphore : public TSemaphore
  191. {
  192.   public:
  193. #if defined(BI_PLAT_WIN32)
  194.     TEventSemaphore(bool manualReset=false, bool initialState=false,
  195.                     const _TCHAR* name = 0, LPSECURITY_ATTRIBUTES sa = 0);
  196.     TEventSemaphore(const _TCHAR* name, bool inherit,
  197.                     uint32 access = SEMAPHORE_ALL_ACCESS);
  198.     TEventSemaphore(THandle handle);
  199. #elif defined(BI_PLAT_OS2)
  200.     TEventSemaphore(bool manualReset=false, bool initialState=false,
  201.                     const _TCHAR* name = 0);
  202.    ~TEventSemaphore();
  203. #endif
  204.  
  205.     void Set();
  206.     void Reset();
  207.     void Pulse();
  208.  
  209. #if defined(BI_PLAT_OS2)
  210.     typedef HEV THandle;
  211.     operator THandle() const;
  212. #endif
  213.  
  214.   private:
  215.     TEventSemaphore(const TMutex&);
  216.     const TEventSemaphore& operator =(const TEventSemaphore&);
  217.  
  218.     virtual void Release();  // Release this event semaphore
  219.  
  220. #if defined(BI_PLAT_OS2)
  221.     THandle Handle;
  222. #endif
  223. };
  224.  
  225. //
  226. // class TSemaphoreSet
  227. // ~~~~~ ~~~~~~~~~~~~~
  228. // Semaphore object aggregator. Used to combine a set of semaphore objects so
  229. // that they can be waited upon (locked) as a group. The lock can wait for any
  230. // one, or all of them. The semaphore objects to be aggregated MUST live at
  231. // least as long as this TSemaphoreSet, as it maintains pointers to them.
  232. //
  233. class _BIDSCLASS TSemaphoreSet
  234. {
  235.   public:
  236.     // sems is initial array of sem ptrs, may be 0 to add sems later,
  237.     // size is maximum sems to hold, -1 means count the 0-terminated array
  238.     // Passing (0,-1) is not valid
  239.     //
  240.     TSemaphoreSet(const TSemaphore* sems[], int size = -1);
  241.    ~TSemaphoreSet();
  242.  
  243.     void Add(const TSemaphore& sem);
  244.     void Remove(const TSemaphore& sem);
  245.     int  GetCount() const;
  246.     const TSemaphore* operator [](int index) const;
  247.  
  248. #if defined(BI_PLAT_WIN32)
  249.     enum TWaitWhat { WaitAny = false, WaitAll = true };
  250.     enum { NoWait = 0, NoLimit = INFINITE };
  251. #elif defined(BI_PLAT_OS2)
  252.     enum TWaitWhat { WaitAny = DCM_WAIT_ANY, WaitAll = DCM_WAIT_ALL };
  253.     enum { NoWait = SEM_IMMEDIATE_RETURN, NoLimit = SEM_INDEFINITE_WAIT };
  254. #endif
  255.  
  256.     class _BIDSCLASS TLock {
  257.       public:
  258.         // Assumes that set is not modified while locked
  259.         //
  260.         TLock(const TSemaphoreSet& set, TWaitWhat wait,
  261.               ulong timeOut = NoLimit, bool alertable = false);
  262.         TLock(ulong msgMask, const TSemaphoreSet& set, TWaitWhat wait,
  263.               ulong timeOut = NoLimit);
  264.        ~TLock();
  265.  
  266.         bool WasAquired() const;    // See if one or more was aquired
  267.         enum {
  268.           AllAquired = -1,   // All semaphores were aquired
  269.           TimedOut   = -2,   // None aquired: timed out
  270.           IoComplete = -3,   //               IO complate alert
  271.           MsgWaiting = -4,   //               Msg waiting
  272.         };
  273.         int  WhichAquired() const;  // See which was aquired >=0, or enum
  274.  
  275.         void Release(bool relinquish = false);
  276.  
  277.       protected:
  278.         bool InitLock(int count, TWaitWhat wait, int index);
  279.  
  280.       private:
  281.         const TSemaphoreSet* Set;
  282.         int   Locked;    // Which one got locked, or wait code
  283.     };
  284.     friend TLock;
  285.  
  286.   private:
  287.     void Release(int index = -1);
  288.  
  289. #if defined(BI_PLAT_WIN32)
  290.     typedef TSemaphore* TSemaphorePtr;
  291.     typedef HANDLE THandle;
  292.  
  293.     const TSemaphore** Sems;    // Array of ptrs to semaphores, packed at head
  294.  
  295. #elif defined(BI_PLAT_OS2)
  296.     SEMRECORD* SemRecord;
  297. #endif
  298.     int   Size;   // Size of array, i.e. maximum object count
  299.     int   Count;  // Count of objects currently in array
  300. };
  301.  
  302. //
  303. // class TCriticalSection
  304. // ~~~~~ ~~~~~~~~~~~~~~~~
  305. // Lightweight intra-process thread synchronization. Can only be used with
  306. // other critical sections, and only within the same process.
  307. //
  308. class TCriticalSection
  309. {
  310.   public:
  311.     TCriticalSection();
  312.    ~TCriticalSection();
  313.  
  314.     class TLock {
  315.       public:
  316.         TLock(const TCriticalSection&);
  317.        ~TLock();
  318.       private:
  319. #if defined(BI_PLAT_WIN32)
  320.         const TCriticalSection& CritSecObj;
  321. #elif defined(BI_PLAT_OS2)
  322.         TMutex::TLock Lck;
  323. #endif
  324.     };
  325.     friend TLock;
  326.     typedef TLock Lock;  // For compatibility with old T-less typename
  327.  
  328.   private:
  329. #if defined(BI_PLAT_WIN32)
  330.     CRITICAL_SECTION CritSec;
  331. #elif defined(BI_PLAT_OS2)
  332.     TMutex CritSec;        // It seems that in OS/2 CritSec blocks all threads
  333. #endif
  334.  
  335.     TCriticalSection(const TCriticalSection&);
  336.     const TCriticalSection& operator =(const TCriticalSection&);
  337. };
  338.  
  339. //
  340. // class TSync
  341. // class TSync::TLock
  342. // ~~~~~ ~~~~~~~~~~~
  343. // TSync provides a system-independent interface to build classes that act like
  344. // monitors, i.e., classes in which only one member can execute on a particular
  345. // instance at any one time. TSync uses TCriticalSection, so it is portable to
  346. // all platforms that TCriticalSection has been ported to.
  347. //
  348. // TSync Public Interface
  349. // ~~~~~~~~~~~~~~~~~~~~~~
  350. // None. TSync can only be a base class.
  351. //
  352. // TSync Protected Interface
  353. // ~~~~~~~~~~~~~~~~~~~~~~~~~
  354. //     TSync(const TSync&);
  355. //                             Copy constructor. Does not copy the
  356. //                             TCriticalSection object.
  357. //
  358. //     const TSync& operator =(const TSync&);
  359. //                             Assignment operator. Does not copy the
  360. //                             TCriticalSection object.
  361. //
  362. //     class TLock;            Handles locking and unlocking of member
  363. //                             functions.
  364. //
  365. // Example
  366. // ~~~~~~~
  367. //     class ThreadSafe : private TSync
  368. //     {
  369. //       public:
  370. //         void f();
  371. //         void g();
  372. //       private:
  373. //         int i;
  374. //     };
  375. //
  376. //     void ThreadSafe::f()
  377. //     {
  378. //       TLock lock(this);
  379. //       if (i == 2)
  380. //         i = 3;
  381. //     }
  382. //
  383. //     void ThreadSafe::g()
  384. //     {
  385. //       TLock lock(this);
  386. //       if (i == 3)
  387. //         i = 2;
  388. //     }
  389. //
  390. class TSync
  391. {
  392.   protected:
  393.     TSync();
  394.     TSync(const TSync&);
  395.     const TSync& operator =(const TSync&);
  396.  
  397.     class TLock : private TCriticalSection::TLock
  398.     {
  399.       public:
  400.         TLock(const TSync*);
  401.       private:
  402.         static const TCriticalSection& GetRef(const TSync*);
  403.     };
  404.     friend TLock;
  405.     typedef TLock Lock;  // For compatibility with old T-less typename
  406.  
  407.   private:
  408.     TCriticalSection CritSec;
  409. };
  410.  
  411. //
  412. // template <class T> class TStaticSync
  413. // template <class T> class TStaticSync::TLock
  414. // ~~~~~~~~ ~~~~~~~~~ ~~~~~ ~~~~~~~~~~~~~~~~~
  415. // TStaticSync provides a system-independent interface to build sets of classes
  416. // that act somewhat like monitors, i.e., classes in which only one member
  417. // function can execute at any one time regardless of which instance it is
  418. // being called on. TStaticSync uses TCriticalSection, so it is portable to all
  419. // platforms that TCriticalSection has been ported to.
  420. //
  421. // TStaticSync Public Interface
  422. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  423. // None. TStaticSync can only be a base class.
  424. //
  425. // TStaticSync Protected Interface
  426. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  427. //     TStaticSync<T>(const TStaticSync<T>&);
  428. //                             Copy constructor. Does not copy the
  429. //                             TCriticalSection object.
  430. //
  431. //     const TStaticSync<T>& operator =(const TStaticSync<T>&);
  432. //                             Assignment operator. Does not copy the
  433. //                             TCriticalSection object.
  434. //
  435. //     class TLock;            Handles locking and unlocking of member
  436. //                             functions.
  437. //
  438. // Example
  439. // ~~~~~~~
  440. //     class ThreadSafe : private TStaticSync<ThreadSafe>
  441. //     {
  442. //       public:
  443. //         void f();
  444. //         void g();
  445. //       private:
  446. //         static int i;
  447. //     };
  448. //
  449. //     void ThreadSafe::f()
  450. //     {
  451. //       TLock lock;
  452. //       if (i == 2)
  453. //         i = 3;
  454. //     }
  455. //
  456. //     void ThreadSafe::g()
  457. //     {
  458. //       TLock lock;
  459. //       if (i == 3)
  460. //         i = 2;
  461. //     }
  462. //
  463. template <class T> class TStaticSync
  464. {
  465.   protected:
  466.     TStaticSync();
  467.     TStaticSync(const TStaticSync<T>&);
  468.     const TStaticSync<T>& operator =(const TStaticSync<T>&);
  469.    ~TStaticSync();
  470.  
  471.     class TLock : private TCriticalSection::TLock
  472.     {
  473.       public:
  474.         TLock() : TCriticalSection::TLock(*TStaticSync<T>::CritSec) {}
  475.     };
  476.     friend TLock;
  477.     typedef TLock Lock;  // For compatibility with old T-less typename
  478.  
  479.   private:
  480.     static TCriticalSection* CritSec;
  481.     static ulong Count;
  482. };
  483.  
  484. //
  485. // class TThread
  486. // ~~~~~ ~~~~~~~
  487. // TThread provides a system-independent interface to threads. With
  488. // suitable underlying implementations the same code can be used under
  489. // OS/2 and Win32.
  490. //
  491. // TThread Public Interface
  492. // ~~~~~~~~~~~~~~~~~~~~~~~~
  493. //     Start();                Begins execution of the thread. Returns
  494. //                             the handle of the thread.
  495. //
  496. //     Suspend();              Suspends execution of the thread.
  497. //     Resume();               Resumes execution of a suspended thread.
  498. //
  499. //     Terminate();            Sets an internal flag that indicates that the
  500. //                             thread should exit. The derived class can check
  501. //                             the state of this flag by calling
  502. //                             ShouldTerminate().
  503. //
  504. //     WaitForExit(ulong timeout = NoLimit);
  505. //                             Blocks the calling thread until the internal
  506. //                             thread exits or until the time specified by
  507. //                             timeout, in milliseconds,expires. A timeout of
  508. //                             NoLimit says to wait indefinitely.
  509. //
  510. //     TerminateAndWait(ulong timeout = NoLimit);
  511. //                             Combines the behavior of Terminate() and
  512. //                             WaitForExit(). Sets an internal flag that
  513. //                             indicates that the thread should exit and blocks
  514. //                             the calling thread until the internal thread
  515. //                             exits or until the time specified by timeout, in
  516. //                             milliseconds, expires. A timeout of NoLimit says
  517. //                             to wait indefinitely.
  518. //
  519. //     GetStatus();            Gets the current status of the thread.
  520. //                             See TThread::Status for possible values.
  521. //
  522. //     GetPriority();          Gets the priority of the thread.
  523. //     SetPriority();          Sets the priority of the thread.
  524. //
  525. //     enum TStatus;           Identifies the states that the class can be in.
  526. //
  527. //         Created             The class has been created but the thread has
  528. //                             not been started.
  529. //         Running             The thread is running.
  530. //
  531. //         Suspended           The thread has been suspended.
  532. //
  533. //         Finished            The thread has finished execution.
  534. //
  535. //         Invalid             The object is invalid. Currently this happens
  536. //                             only when the operating system is unable to
  537. //                             start the thread.
  538. //
  539. //     class TThreadError;     The error class that defines the objects that
  540. //                             are thrown when an error occurs.
  541. //
  542. // TThread::ThreadError Public Interface
  543. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  544. //     enum TErrorType;        Identifies the type of error that occurred.
  545. //
  546. //         SuspendBeforeRun    The user called Suspend() on an object
  547. //                             before calling Start().
  548. //
  549. //         ResumeBeforeRun     The user called Resume() on an object
  550. //                             before calling Start().
  551. //
  552. //         ResumeDuringRun     The user called Resume() on a thread that
  553. //                             was not Suspended.
  554. //
  555. //         SuspendAfterExit    The user called Suspend() on an object
  556. //                             whose thread had already exited.
  557. //
  558. //         ResumeAfterExit     The user called Resume() on an object
  559. //                             whose thread had already exited.
  560. //
  561. //         CreationFailure     The operating system was unable to create
  562. //                             the thread.
  563. //
  564. //         DestroyBeforeExit   The object's destructor was invoked
  565. //                             its thread had exited.
  566. //
  567. //         AssignError         An attempt was made to assign to an
  568. //                             object that was not in either the
  569. //                             Created or the Finished state.
  570. //
  571. //     TErrorType GetErrorType() const;
  572. //                             Returns a code indicating the type of
  573. //                             error that occurred.
  574. //
  575. //     string why();           Returns a string that describes the
  576. //                             error. Inherited from xmsg.
  577. //
  578. // TThread Protected Interface
  579. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  580. //     TThread();              Creates an object of type TThread.
  581. //     virtual ~TThread();     Destroys the object.
  582. //
  583. //     const TThread& operator =(const TThread&);
  584. //                             The target object must be in either the
  585. //                             Created state or the Finished state. If
  586. //                             so, puts the object into the Created
  587. //                             state. If the object is not in either the
  588. //                             Created state or the Finished state it
  589. //                             is an error and an exception will be
  590. //                             thrown.
  591. //
  592. //     TThread(const TThread&);
  593. //                             Pts the object into the Created
  594. //                             state, just like the default constructor.
  595. //                             Does not copy any of the internal details
  596. //                             of the thread being copied.
  597. //
  598. //     virtual ulong Run() = 0;
  599. //                             The function that does the work. Calling
  600. //                             Start() creates a thread that begins
  601. //                             executing Run() with the 'this' pointer
  602. //                             pointing to the TThread-based object.
  603. //
  604. //     int ShouldTerminate() const;
  605. //                             Returns a non-zero value to indicate
  606. //                             that Terminate() or TerminateAndWait()
  607. //                             has been called. If this capability is
  608. //                             being used, the thread should call
  609. //                             ShouldTerminate() regularly, and if it
  610. //                             returns a non-zero value the thread
  611. //                             finish its processing and exit.
  612. //
  613. // Example
  614. // ~~~~~~~
  615. //     class TimerThread : public TThread
  616. //     {
  617. //       public:
  618. //         TimerThread() : Count(0) {}
  619. //       private:
  620. //         int Run();
  621. //         int Count;
  622. //     };
  623. //
  624. //     int TimerThread::Run()
  625. //     {
  626. //       // loop 10 times
  627. //       while (Count++ < 10) {
  628. //         Sleep(1000);    // delay 1 second
  629. //         cout << "Iteration " << Count << endl;
  630. //       }
  631. //       return 0;
  632. //     }
  633. //
  634. //     int main()
  635. //     {
  636. //       TimerThread timer;
  637. //       timer.Start();
  638. //       Sleep(20000);     // delay 20 seconds
  639. //       return 0;
  640. //     }
  641. //
  642. // Internal States
  643. // ~~~~~~~~~~~~~~~
  644. // Created:    the object has been created but its thread has not been
  645. //             started. The only valid transition from this state is
  646. //             to Running, which happens on a call to Start(). In
  647. //             particular, a call to Suspend() or Resume() when the
  648. //             object is in this state is an error and will throw an
  649. //             exception.
  650. //
  651. // Running:    the thread has been started successfully. There are two
  652. //             transitions from this state:
  653. //
  654. //                 When the user calls Suspend() the object moves into
  655. //                 the Suspended state.
  656. //
  657. //                 When the thread exits the object moves into the
  658. //                 Finished state.
  659. //
  660. //             Calling Resume() on an object that is in the Running
  661. //             state is an error and will throw an exception.
  662. //
  663. // Suspended:  the thread has been suspended by the user. Subsequent
  664. //             calls to Suspend() nest, so there must be as many calls
  665. //             to Resume() as there were to Suspend() before the thread
  666. //             actually resumes execution.
  667. //
  668. // Finished:   the thread has finished executing. There are no valid
  669. //             transitions out of this state. This is the only state
  670. //             from which it is legal to invoke the destructor for the
  671. //             object. Invoking the destructor when the object is in
  672. //             any other state is an error and will throw an exception.
  673. //
  674. class _BIDSCLASS TThread
  675. {
  676.   public:
  677. #if defined(BI_PLAT_WIN32)
  678.     enum { NoLimit = INFINITE };
  679.     typedef HANDLE THandle;
  680. #elif defined(BI_PLAT_OS2)
  681.     enum { NoLimit = DCWW_WAIT };
  682.     typedef TID THandle;
  683. #endif
  684.  
  685.     // Attach to the current running (often primary) thread
  686.     //
  687.     enum TCurrent {Current};
  688.     TThread(TCurrent);
  689.  
  690.     enum TStatus { Created, Running, Suspended, Finished, Invalid };
  691.  
  692.     THandle Start();
  693.     ulong   Suspend();
  694.     ulong   Resume();
  695.     bool    Sleep(long timeMS, bool alertable = false);
  696.  
  697.     virtual void    Terminate();
  698.     ulong   WaitForExit(ulong timeout = NoLimit);
  699.     ulong   TerminateAndWait(ulong timeout = NoLimit);
  700.  
  701.     TStatus GetStatus() const;
  702.     uint32  GetExitCode() const;
  703.  
  704.     enum TPriority {
  705.       Idle         = THREAD_PRIORITY_IDLE,          // -15
  706.       Lowest       = THREAD_PRIORITY_LOWEST,        //  -2
  707.       BelowNormal  = THREAD_PRIORITY_BELOW_NORMAL,  //  -1
  708.       Normal       = THREAD_PRIORITY_NORMAL,        //   0
  709.       AboveNormal  = THREAD_PRIORITY_ABOVE_NORMAL,  //   1
  710.       Highest      = THREAD_PRIORITY_HIGHEST,       //   2
  711.       TimeCritical = THREAD_PRIORITY_TIME_CRITICAL, //  15
  712.     };
  713.  
  714.     int GetPriority() const;
  715.     int SetPriority(int);   // Can pass a TPriority for simplicity
  716.  
  717.     class TThreadError : public xmsg
  718.     {
  719.       public:
  720.         enum TErrorType {
  721.           SuspendBeforeRun,
  722.           ResumeBeforeRun,
  723.           ResumeDuringRun,
  724.           SuspendAfterExit,
  725.           ResumeAfterExit,
  726.           CreationFailure,
  727.           DestroyBeforeExit,
  728.           AssignError,
  729.           NoMTRuntime,
  730.         };
  731.         typedef TErrorType ErrorType;
  732.         TErrorType GetErrorType() const;
  733.  
  734.       private:
  735.         TThreadError(TErrorType type);
  736.         static string MakeString(ErrorType type);
  737.         TErrorType Type;
  738.       friend TThread;
  739.     };
  740.  
  741.     typedef TStatus Status;     // For compatibility with old T-less typenames
  742.     typedef TThreadError ThreadError;
  743.  
  744.   protected:
  745.     TThread();          // Create a thread. Derived class overrides Run()
  746.  
  747.     // Copying a thread puts the target into the Created state
  748.     //
  749.     TThread(const TThread&);
  750.     const TThread& operator =(const TThread&);
  751.  
  752.     virtual ~TThread();
  753.  
  754.     bool    ShouldTerminate() const;
  755.     void    Exit(ulong code);  // Alternative to returning from Run()
  756.  
  757.   private:
  758.     virtual int Run();         
  759.  
  760.     TStatus CheckStatus() const;
  761.  
  762. #if defined(BI_MULTI_THREAD_RTL)
  763.     static void _USERENTRY Execute(void* thread);
  764. #elif defined(BI_PLAT_WIN32)
  765.     static ulong __stdcall Execute(void* thread);
  766. #elif defined(BI_PLAT_OS2)
  767.     static void __stdcall Execute(ulong);
  768. #endif
  769.  
  770. #if defined(BI_PLAT_WIN32)
  771.     uint32 ThreadId;
  772. #elif defined(BI_PLAT_OS2)
  773.     ulong Priority;
  774. #endif
  775.     THandle Handle;
  776.     mutable TStatus Stat;
  777.     bool TerminationRequested;
  778.     bool Attached;
  779. };
  780.  
  781. //----------------------------------------------------------------------------
  782. // Inline implementation
  783. //
  784.  
  785. #if defined(BI_PLAT_WIN32)
  786.  
  787. //----------------------------------------
  788. // TSemaphore Win32
  789.  
  790. //
  791. inline TSemaphore::~TSemaphore()
  792. {
  793.   ::CloseHandle(Handle);
  794. }
  795.  
  796. //
  797. inline TSemaphore::operator TSemaphore::THandle() const
  798. {
  799.   return Handle;
  800. }
  801.  
  802. //
  803. inline TSemaphore::TLock::TLock(const TSemaphore& sem, ulong timeOut, bool alertable)
  804. :
  805.   Sem(0)
  806. {
  807.   if (::WaitForSingleObjectEx(sem, timeOut, alertable) == 0)
  808.     Sem = &sem;
  809. }
  810.  
  811. //
  812. inline TSemaphore::TLock::~TLock()
  813. {
  814.   Release();
  815. }
  816.  
  817. //
  818. inline bool TSemaphore::TLock::WasAquired() const
  819. {
  820.   return Sem != 0;
  821. }
  822.  
  823. //
  824. // Release but hang on to the semaphore
  825. //
  826. inline void TSemaphore::TLock::Release(bool relinquish)
  827. {
  828.   if (Sem) {
  829.     CONST_CAST(TSemaphore*,Sem)->Release();
  830.     if (relinquish)
  831.       Sem = 0;
  832.   }
  833. }
  834.  
  835. //----------------------------------------
  836. // TMutex Win32
  837.  
  838. //
  839. inline TMutex::TMutex(const _TCHAR* name, LPSECURITY_ATTRIBUTES sa)
  840.  : Shared(false)
  841. {
  842.   Handle = ::CreateMutex(sa, false, name);  // don't aquire now
  843.   if (Handle && (GetLastError() == ERROR_ALREADY_EXISTS))
  844.     Shared = true;
  845. }
  846.  
  847. //
  848. // Open an existing mutex. Fails if not there.
  849. //
  850. inline TMutex::TMutex(const _TCHAR* name, bool inherit, uint32 access)
  851.   : Shared(false)
  852. {
  853.   Handle = ::OpenMutex(access, inherit, name);
  854.   if (Handle)
  855.     Shared = true;
  856. }
  857.  
  858. //
  859. //
  860. //
  861. inline TMutex::TMutex(THandle handle)
  862.   : Shared(false)
  863. {
  864.   if (::DuplicateHandle(::GetCurrentProcess(), handle,
  865.                         ::GetCurrentProcess(), &Handle,
  866.                         0, false, DUPLICATE_SAME_ACCESS))
  867.   {
  868.     Shared = true;
  869.   }
  870. }
  871.  
  872. //
  873. //
  874. //
  875. inline bool TMutex::IsShared()
  876. {
  877.   return Shared;
  878. }
  879.  
  880. //----------------------------------------
  881. // TCountedSemaphore Win32
  882.  
  883. //
  884. inline TCountedSemaphore::TCountedSemaphore(int initialCount, int maxCount,
  885.                                             const _TCHAR* name,
  886.                                             LPSECURITY_ATTRIBUTES sa)
  887. {
  888.   Handle = ::CreateSemaphore(sa, initialCount, maxCount, name);
  889. }
  890.  
  891. //
  892. inline TCountedSemaphore::TCountedSemaphore(const _TCHAR* name, bool inherit,
  893.                                             uint32 access)
  894. {
  895.   Handle = ::OpenSemaphore(access, inherit, name);
  896. }
  897.  
  898. //
  899. inline TCountedSemaphore::TCountedSemaphore(THandle handle)
  900. {
  901.   ::DuplicateHandle(::GetCurrentProcess(), handle,
  902.                     ::GetCurrentProcess(), &Handle,
  903.                     0, false, DUPLICATE_SAME_ACCESS);
  904. }
  905.  
  906. //----------------------------------------
  907. // TEventSemaphore Win32
  908.  
  909. inline TEventSemaphore::TEventSemaphore(bool manualReset, bool initialState,
  910.                                         const _TCHAR* name,
  911.                                         LPSECURITY_ATTRIBUTES sa)
  912. {
  913.   Handle = ::CreateEvent(sa, manualReset, initialState, name);
  914. }
  915.  
  916. //
  917. inline TEventSemaphore::TEventSemaphore(const _TCHAR* name, bool inherit,
  918.                                         uint32 access)
  919. {
  920.   Handle = ::OpenEvent(access, inherit, name);
  921. }
  922.  
  923. //
  924. inline TEventSemaphore::TEventSemaphore(THandle handle)
  925. {
  926.   ::DuplicateHandle(::GetCurrentProcess(), handle,
  927.                     ::GetCurrentProcess(), &Handle,
  928.                     0, false, DUPLICATE_SAME_ACCESS);
  929. }
  930.  
  931. inline void TEventSemaphore::Set()
  932. {
  933.   ::SetEvent(*this);
  934. }
  935.  
  936. inline void TEventSemaphore::Reset()
  937. {
  938.   ::ResetEvent(*this);
  939. }
  940.  
  941. inline void TEventSemaphore::Pulse()
  942. {
  943.   ::PulseEvent(*this);
  944. }
  945.  
  946. //----------------------------------------
  947. // TSemaphoreSet Win32
  948.  
  949. inline int TSemaphoreSet::GetCount() const
  950. {
  951.   return Count;
  952. }
  953.  
  954. inline const TSemaphore* TSemaphoreSet::operator [](int index) const
  955. {
  956.   return (index >= 0 && index < Count) ? Sems[index] : 0;
  957. }
  958.  
  959. //
  960. inline bool TSemaphoreSet::TLock::WasAquired() const
  961. {
  962.   return Set != 0;
  963. }
  964.  
  965. //
  966. // Which one was locked, all locked code, or lock fail code
  967. //
  968. inline int TSemaphoreSet::TLock::WhichAquired() const
  969. {
  970.   return Locked;
  971. }
  972.  
  973. #elif defined(BI_PLAT_OS2)
  974.  
  975. //----------------------------------------
  976. // TMutex OS/2
  977.  
  978. //
  979. inline TMutex::TMutex()
  980. {
  981.   ::DosCreateMutexSem(0, &Handle, 0, false);
  982. }
  983.  
  984. //
  985. inline TMutex::~TMutex()
  986. {
  987.   ::DosCloseMutexSem(Handle);
  988. }
  989.  
  990. //
  991. inline TMutex::operator TMutex::THandle() const
  992. {
  993.   return Handle;
  994. }
  995.  
  996. //
  997. inline TMutex::TLock::TLock(const TMutex& mutex, ulong timeOut)
  998. :
  999.   MutexObj(mutex)
  1000. {
  1001.   ::DosRequestMutexSem(MutexObj, timeOut);
  1002. }
  1003.  
  1004. //
  1005. inline TMutex::TLock::~TLock()
  1006. {
  1007.   Release();
  1008. }
  1009.  
  1010. //
  1011. inline void TMutex::TLock::Release()
  1012. {
  1013.   ::DosReleaseMutexSem(MutexObj);
  1014. }
  1015.  
  1016. #endif
  1017.  
  1018. //----------------------------------------------------------------------------
  1019. // TCriticalSection Win32
  1020. //
  1021. #if defined(BI_PLAT_WIN32)
  1022.  
  1023. //
  1024. // Use system call to initialize the CRITICAL_SECTION object.
  1025. //
  1026. inline TCriticalSection::TCriticalSection()
  1027. {
  1028.   ::InitializeCriticalSection(CONST_CAST(CRITICAL_SECTION*,&CritSec));
  1029. }
  1030.  
  1031. //
  1032. // Use system call to destroy the CRITICAL_SECTION object.
  1033. //
  1034. inline TCriticalSection::~TCriticalSection()
  1035. {
  1036.   ::DeleteCriticalSection(CONST_CAST(CRITICAL_SECTION*,&CritSec));
  1037. }
  1038.  
  1039. //
  1040. // Use system call to lock the CRITICAL_SECTION object.
  1041. //
  1042. inline TCriticalSection::TLock::TLock(const TCriticalSection& sec)
  1043. :
  1044.   CritSecObj(sec)
  1045. {
  1046.   ::EnterCriticalSection(CONST_CAST(CRITICAL_SECTION*,&CritSecObj.CritSec));
  1047. }
  1048.  
  1049. //
  1050. // Use system call to unlock the CRITICAL_SECTION object.
  1051. //
  1052. inline TCriticalSection::TLock::~TLock()
  1053. {
  1054.   ::LeaveCriticalSection(CONST_CAST(CRITICAL_SECTION*,&CritSecObj.CritSec));
  1055. }
  1056.  
  1057. //
  1058. // TCriticalSection OS2
  1059. //
  1060. #elif defined(BI_PLAT_OS2)
  1061.  
  1062. //
  1063. // Compiler takes care of constructing the TMutex data object.
  1064. //
  1065. inline TCriticalSection::TCriticalSection()
  1066. {
  1067. }
  1068.  
  1069. //
  1070. // Compiler takes care of destroying the TMutex data object.
  1071. //
  1072. inline TCriticalSection::~TCriticalSection()
  1073. {
  1074. }
  1075.  
  1076. //
  1077. // Construct the TMutex::TLock object to lock the specified TCriticalSection
  1078. // object.
  1079. //
  1080. inline TCriticalSection::TLock::TLock(const TCriticalSection& sec)
  1081. :
  1082.   Lck(sec.CritSec)
  1083. {
  1084. }
  1085.  
  1086. //
  1087. // Compiler takes care of destroying the TMutex::TLock data object, which
  1088. // releases the lock.
  1089. //
  1090. inline TCriticalSection::TLock::~TLock()
  1091. {
  1092. }
  1093.  
  1094. #endif
  1095.  
  1096. //----------------------------------------------------------------------------
  1097.  
  1098. //
  1099. // Copy constructor does not copy the TCriticalSection object,
  1100. // since the new object is not being used in any of its own
  1101. // member functions. This means that the new object must start
  1102. // in an unlocked state.
  1103. //
  1104. inline TSync::TSync()
  1105. {
  1106. }
  1107.  
  1108. //
  1109. inline TSync::TSync(const TSync&)
  1110. {
  1111. }
  1112.  
  1113. //
  1114. // Does not copy the TCriticalSection object, since the new  object is not
  1115. // being used in any of its own member functions.
  1116. // This means that the new object must start in an unlocked state.
  1117. //
  1118. inline const TSync& TSync::operator =(const TSync&)
  1119. {
  1120.   return *this;
  1121. }
  1122.  
  1123. //
  1124. // Locks the TCriticalSection object in the TSync object.
  1125. //
  1126. inline TSync::TLock::TLock(const TSync* sync)
  1127. :
  1128.   TCriticalSection::TLock(GetRef(sync))
  1129. {
  1130. }
  1131.  
  1132. //
  1133. // Returns a reference to the TCriticalSection object contained in the TSync
  1134. // object.
  1135. //
  1136. // In the diagnostic version, checks for a null pointer.
  1137. //
  1138. inline const TCriticalSection& TSync::TLock::GetRef(const TSync* sync)
  1139. {
  1140.   CHECK(sync != 0);
  1141.   return sync->CritSec;
  1142. }
  1143.  
  1144. //----------------------------------------------------------------------------
  1145.  
  1146. //
  1147. // Instantiate the data members.
  1148. //
  1149. template <class T> TCriticalSection* TStaticSync<T>::CritSec;
  1150. template <class T> ulong TStaticSync<T>::Count;
  1151.  
  1152. //
  1153. // If this is the first TStaticSync<T> object to be constructed, create the
  1154. // semaphore.
  1155. //
  1156. // The copy constructor only has to increment the count, since there will
  1157. // already be at least one TStaticSync<T> object, namely, the one being copied.
  1158. //
  1159. template <class T> inline TStaticSync<T>::TStaticSync()
  1160. {
  1161.   if (Count++ == 0)
  1162.     CritSec = new TCriticalSection;
  1163. }
  1164.  
  1165. template <class T> inline TStaticSync<T>::TStaticSync(const TStaticSync<T>&)
  1166. {
  1167.   Count++;
  1168. }
  1169.  
  1170. //
  1171. // TStaticSync<T> assignment operator
  1172. //
  1173. template <class T>
  1174. inline const TStaticSync<T>& TStaticSync<T>::operator =(const TStaticSync<T>&)
  1175. {
  1176.   return *this;
  1177. }
  1178.  
  1179. //
  1180. // If this is the only remaining TStaticSync<T> object, destroy the semaphore.
  1181. //
  1182. template <class T> inline TStaticSync<T>::~TStaticSync()
  1183. {
  1184.   if (--Count == 0)
  1185.     delete CritSec;
  1186. }
  1187.  
  1188. //----------------------------------------------------------------------------
  1189.  
  1190. //
  1191. // Put this tread to sleep for a given number of milliseconds, with an optional
  1192. // wakeup on an IO completion. Return true if wakeup is due to IO completion.
  1193. //
  1194. inline bool TThread::Sleep(long timeMS, bool alertable)
  1195. {
  1196. #if defined(BI_PLAT_WIN32)
  1197.   return ::SleepEx(timeMS, alertable) == WAIT_IO_COMPLETION;
  1198. #elif defined(BI_PLAT_OS2)
  1199. #endif
  1200. }
  1201.  
  1202. //
  1203. // If the thread is marked as Running it may have terminated without our
  1204. // knowing it, so we have to check.
  1205. //
  1206. inline TThread::TStatus TThread::GetStatus() const
  1207. {
  1208.   if (Stat == Running)
  1209. #if defined(BI_NO_MUTABLE)
  1210.     CONST_CAST(TThread*,this)->Stat = CheckStatus();
  1211. #else
  1212.     Stat = CheckStatus();
  1213. #endif
  1214.   return Stat;
  1215. }
  1216.  
  1217. //
  1218. inline uint32  TThread::GetExitCode() const
  1219. {
  1220.   uint32 code;
  1221.   ::GetExitCodeThread(Handle, &code);
  1222.   return code;
  1223. }
  1224.  
  1225. //
  1226. // Direct OS call under Win32. Return stored value under OS/2.
  1227. //
  1228. inline int TThread::GetPriority() const
  1229. {
  1230. #if defined(BI_PLAT_WIN32)
  1231.   return ::GetThreadPriority(Handle);
  1232. #elif defined(BI_PLAT_OS2)
  1233.   return Priority;
  1234. #endif
  1235. }
  1236.  
  1237. //
  1238. inline bool TThread::ShouldTerminate() const
  1239. {
  1240.   return TerminationRequested;
  1241. }
  1242.  
  1243. //
  1244. inline TThread::TThreadError::TErrorType TThread::TThreadError::GetErrorType() const
  1245. {
  1246.   return Type;
  1247. }
  1248.  
  1249. #if defined(BI_NAMESPACE)
  1250. }   // namespace ClassLib
  1251. #endif
  1252.  
  1253. #if defined(BI_CLASSLIB_NO_po)
  1254. # pragma option -po.
  1255. #endif
  1256.  
  1257. #endif  // CLASSLIB_THREAD_H
  1258.