home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 May / Pcwk5b98.iso / Borland / Cplus45 / BC45 / CLASSINC.PAK / THREAD.H < prev    next >
C/C++ Source or Header  |  1995-08-29  |  51KB  |  1,199 lines

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