- BORLAND/: Borland C++ 4.52 (chosen over 4.5 by byte-match: CODE/RP/CW32.LIB
is identical to 4.52's install lib). BCC32/TLINK32/TLIB/MAKE run natively on
Win11; CODE/BT/OPT.MAK is the shipped BTL4OPT.EXE's exact flag recipe
(extender = Borland PowerPack DPMI32, not Phar Lap TNT).
- restoration/source410/: the literal 1995-form reconstruction of the missing
BT game source (never mixed into CODE/). Round 1-3 state:
* 6 of 10 surviving original TUs COMPILE CLEAN under the period toolchain
(BTMSSN, BTCNSL, BTSCNRL, BTTEAM, BTL4MODE, BTL4ARND) - first builds
since 1996.
* BT_L4/BTL4APP.CPP pilot reconstruction: 12/12 functions, Fail() lands on
its binary-recorded line 400 exactly.
* BT/BTCNSL.HPP: console wire IDs recovered from the binary's ctors
(Killed=9, Damaged=10, ScoreUpdate=13, DeathWithoutHonor=15 [T1];
TeamScore=12 flagged [T4]).
* MUNGA/: 8 engine-header backfills back-dated from the BT412 WinTesla tree
(VDATA numbering decomp-verified; AUDREND's OpenAL-era virtual removed -
the period compiler is the drift detector).
* Tooling: backdate.py (WinTesla->1995 header transform), compile410.sh
(per-TU verification sweep under authentic OPT.MAK flags).
* README: corrected roadmap - MECH.HPP is the capstone grown with the mech
TU reconstructions; BTREG.CPP green = the header-family milestone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1199 lines
50 KiB
C++
1199 lines
50 KiB
C++
/*------------------------------------------------------------------------*/
|
|
/* */
|
|
/* THREAD.H */
|
|
/* */
|
|
/* Copyright (c) 1993, 1994 Borland International */
|
|
/* All Rights Reserved */
|
|
/* */
|
|
/* Defines the class TMutex and its nested class Lock. */
|
|
/* Defines the class TCriticalSection and its nested class Lock. */
|
|
/* Defines the class TSync and its nested class Lock. */
|
|
/* Defines the template TStaticSync and its nested class Lock. */
|
|
/* Defines the class TThread. */
|
|
/* */
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
#if !defined( CLASSLIB_THREAD_H )
|
|
#define CLASSLIB_THREAD_H
|
|
|
|
#if !defined( __CSTRING_H )
|
|
#include <cstring.h>
|
|
#endif
|
|
|
|
#if defined( _Windows )
|
|
# if defined( __WINDOWS_H )
|
|
# if !defined( STRICT )
|
|
# error #define <windows.h> must be preceded by #define STRICT
|
|
# endif
|
|
# else
|
|
# define STRICT
|
|
# include <windows.h>
|
|
# endif
|
|
#elif defined( __OS2__ )
|
|
# if defined( __OS2_H )
|
|
# if !defined( INCL_BASE )
|
|
# error #include <os2.h> must be preceded by #define INCL_PM
|
|
# endif
|
|
# else
|
|
# define INCL_BASE
|
|
# include <os2.h>
|
|
# endif
|
|
#endif
|
|
|
|
#if !defined( __CHECKS_H )
|
|
#include <checks.h>
|
|
#endif // __CHECKS_H
|
|
|
|
#if !defined( CLASSLIB_DEFS_H )
|
|
#include <classlib/defs.h>
|
|
#endif
|
|
|
|
#if !defined(BI_MULTI_THREAD)
|
|
#error Thread classes require multi-threaded operating system.
|
|
#endif
|
|
|
|
#if defined( BI_CLASSLIB_NO_po )
|
|
#pragma option -po-
|
|
#endif
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
/* */
|
|
/* class TMutex; */
|
|
/* class TMutex::Lock; */
|
|
/* */
|
|
/* TMutex provides a system-independent interface to critical */
|
|
/* sections in threads. With suitable underlying implementations the */
|
|
/* same code can be used under OS/2 and Windows NT. */
|
|
/* */
|
|
/* An object of type TMutex can be used in conjunction with */
|
|
/* objects of type TMutex::Lock to guarantee that only one */
|
|
/* thread can be executing any of the code sections protected by the */
|
|
/* lock at any given time. */
|
|
/* */
|
|
/* The differences between the classes TCriticalSection and TMutex are */
|
|
/* that a timeout can be specified when creating a Lock on a TMutex */
|
|
/* object, and that a TMutex object has a HANDLE which can be used */
|
|
/* outside the class. This mirrors the distinction made in Windows NT */
|
|
/* between a CRITICALSECTION and a Mutex. Under NT a TCriticalSection */
|
|
/* object is much faster than a TMutex object. Under operating systems */
|
|
/* that don't make this distinction a TCriticalSection object can use */
|
|
/* the same underlying implementation as a TMutex, losing the speed */
|
|
/* advantage that it has under NT. */
|
|
/* */
|
|
/* TMutex Public Interface */
|
|
/* --------------------------------- */
|
|
/* */
|
|
/* TMutex(); Constructor. Takes no parameters. */
|
|
/* */
|
|
/* ~TMutex(); Destructor. */
|
|
/* */
|
|
/* operator HANDLE() const; (NT) */
|
|
/* operator HMTX() const; (OS/2) */
|
|
/* Returns a handle to the TMutex object, */
|
|
/* for use in OS calls that require it. */
|
|
/* */
|
|
/* class Lock; Handles locking and unlocking of */
|
|
/* critical sections. */
|
|
/* */
|
|
/* */
|
|
/* TMutex::Lock Public Interface */
|
|
/* --------------------------------------- */
|
|
/* */
|
|
/* Lock( const TMutex&, */
|
|
/* unsigned long timeOut = NoLimit ); */
|
|
/* */
|
|
/* Request a lock on the TCriticalSection */
|
|
/* object. If no Lock object in a different */
|
|
/* thread from the calling thread holds */
|
|
/* a lock on that object the lock is */
|
|
/* allowed and execution continues. If */
|
|
/* another thread holds a lock on that */
|
|
/* object the requesting thread is blocked */
|
|
/* until the owning thread has released all */
|
|
/* of its locks. */
|
|
/* */
|
|
/* ~Lock(); Releases the lock. */
|
|
/* */
|
|
/* Example */
|
|
/* ------- */
|
|
/* */
|
|
/* TMutex LockF; */
|
|
/* */
|
|
/* void f() */
|
|
/* { */
|
|
/* TMutex::Lock lock(LockF); */
|
|
/* // critical processing goes here */
|
|
/* } */
|
|
/* */
|
|
/* Only one thread of execution will be allowed to execute the critical */
|
|
/* code inside f() at any one time. */
|
|
/* */
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
class TMutex
|
|
{
|
|
|
|
public:
|
|
|
|
#if defined( __WIN32__ )
|
|
// Windows NT
|
|
enum { NoLimit = -1 };
|
|
typedef HANDLE THandle;
|
|
#elif defined( __OS2__ )
|
|
// OS/2
|
|
enum { NoLimit = SEM_INDEFINITE_WAIT };
|
|
typedef HMTX THandle;
|
|
#endif
|
|
|
|
TMutex();
|
|
~TMutex();
|
|
|
|
operator THandle() const; // HANDLE() under NT
|
|
// HMTX() under OS/2
|
|
|
|
class Lock
|
|
{
|
|
public:
|
|
Lock( const TMutex&, unsigned long timeOut = NoLimit );
|
|
~Lock();
|
|
|
|
void Release();
|
|
|
|
private:
|
|
const TMutex& MutexObj;
|
|
|
|
};
|
|
|
|
friend Lock;
|
|
|
|
private:
|
|
|
|
THandle Handle;
|
|
|
|
TMutex( const TMutex& );
|
|
const TMutex& operator = ( const TMutex& );
|
|
|
|
};
|
|
|
|
|
|
#if defined( __WIN32__ )
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TMutex constructor
|
|
//
|
|
// WIN32
|
|
//
|
|
|
|
inline TMutex::TMutex()
|
|
{
|
|
Handle = ::CreateMutex( 0, FALSE, 0 );
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TMutex destructor
|
|
//
|
|
// WIN32
|
|
//
|
|
|
|
inline TMutex::~TMutex()
|
|
{
|
|
::CloseHandle(Handle);
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TMutex::operator THandle()
|
|
//
|
|
// WIN32
|
|
//
|
|
|
|
inline TMutex::operator TMutex::THandle() const
|
|
{
|
|
return Handle;
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TMutex::Lock constructor
|
|
//
|
|
// WIN32
|
|
//
|
|
|
|
inline TMutex::Lock::Lock( const TMutex& mutex, unsigned long timeOut ) :
|
|
MutexObj(mutex)
|
|
{
|
|
::WaitForSingleObject( MutexObj, timeOut );
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TMutex::Lock destructor
|
|
//
|
|
// WIN32
|
|
//
|
|
|
|
inline TMutex::Lock::~Lock()
|
|
{
|
|
Release();
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TMutex::Lock::Release()
|
|
//
|
|
// WIN32
|
|
//
|
|
|
|
inline void TMutex::Lock::Release()
|
|
{
|
|
::ReleaseMutex(MutexObj);
|
|
}
|
|
|
|
#elif defined( __OS2__ )
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TMutex constructor
|
|
//
|
|
// OS/2
|
|
//
|
|
|
|
inline TMutex::TMutex()
|
|
{
|
|
::DosCreateMutexSem( 0, &Handle, 0, FALSE );
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TMutex destructor
|
|
//
|
|
// OS/2
|
|
//
|
|
|
|
inline TMutex::~TMutex()
|
|
{
|
|
::DosCloseMutexSem(Handle);
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TMutex::operator THandle()
|
|
//
|
|
// OS/2
|
|
//
|
|
|
|
inline TMutex::operator TMutex::THandle() const
|
|
{
|
|
return Handle;
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TMutex::Lock constructor
|
|
//
|
|
// OS/2
|
|
//
|
|
|
|
inline TMutex::Lock::Lock( const TMutex& mutex, unsigned long timeOut ) :
|
|
MutexObj(mutex)
|
|
{
|
|
::DosRequestMutexSem( MutexObj, timeOut );
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TMutex::Lock destructor
|
|
//
|
|
// OS/2
|
|
//
|
|
|
|
inline TMutex::Lock::~Lock()
|
|
{
|
|
Release();
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TMutex::Lock::Release()
|
|
//
|
|
// OS/2
|
|
//
|
|
|
|
inline void TMutex::Lock::Release()
|
|
{
|
|
::DosReleaseMutexSem(MutexObj);
|
|
}
|
|
|
|
#endif
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
/* */
|
|
/* class TCriticalSection; */
|
|
/* class TCriticalSection::Lock; */
|
|
/* */
|
|
/* TCriticalSection provides a system-independent interface to critical */
|
|
/* sections in threads. With suitable underlying implementations the */
|
|
/* same code can be used under OS/2 and Windows NT. */
|
|
/* */
|
|
/* An object of type TCriticalSection can be used in conjunction with */
|
|
/* objects of type TCriticalSection::Lock to guarantee that only one */
|
|
/* thread can be executing any of the code sections protected by the */
|
|
/* lock at any given time. */
|
|
/* */
|
|
/* The differences between the classes TCriticalSection and TMutex are */
|
|
/* that a timeout can be specified when creating a Lock on a TMutex */
|
|
/* object, and that a TMutex object has a HANDLE which can be used */
|
|
/* outside the class. This mirrors the distinction made in Windows NT */
|
|
/* between a CRITICALSECTION and a Mutex. Under NT a TCriticalSection */
|
|
/* object is much faster than a TMutex object. Under operating systems */
|
|
/* that don't make this distinction a TCriticalSection object can use */
|
|
/* the same underlying implementation as a TMutex, losing the speed */
|
|
/* advantage that it has under NT. */
|
|
/* */
|
|
/* TCriticalSection Public Interface */
|
|
/* --------------------------------- */
|
|
/* */
|
|
/* TCriticalSection(); Constructor. Takes no parameters. */
|
|
/* */
|
|
/* ~TCriticalSection(); Destructor. */
|
|
/* */
|
|
/* class Lock; Handles locking and unlocking of */
|
|
/* critical sections. */
|
|
/* */
|
|
/* TCriticalSection::Lock Public Interface */
|
|
/* --------------------------------------- */
|
|
/* */
|
|
/* Lock( const TCriticalSection& ); */
|
|
/* */
|
|
/* Request a lock on the TCriticalSection */
|
|
/* object. If no Lock object in a different */
|
|
/* thread from the calling thread holds */
|
|
/* a lock on that object the lock is */
|
|
/* allowed and execution continues. If */
|
|
/* another thread holds a lock on that */
|
|
/* object the requesting thread is blocked */
|
|
/* until the owning thread has released all */
|
|
/* of its locks. */
|
|
/* */
|
|
/* ~Lock(); Releases the lock. */
|
|
/* */
|
|
/* Example */
|
|
/* ------- */
|
|
/* */
|
|
/* TCriticalSection LockF; */
|
|
/* */
|
|
/* void f() */
|
|
/* { */
|
|
/* TCriticalSection::Lock lock(LockF); */
|
|
/* // critical processing goes here */
|
|
/* } */
|
|
/* */
|
|
/* Only one thread of execution will be allowed to execute the critical */
|
|
/* code inside f() at any one time. */
|
|
/* */
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
class TCriticalSection
|
|
{
|
|
|
|
public:
|
|
|
|
TCriticalSection();
|
|
~TCriticalSection();
|
|
|
|
class Lock
|
|
{
|
|
public:
|
|
Lock( const TCriticalSection& );
|
|
~Lock();
|
|
private:
|
|
#if defined( __WIN32__ )
|
|
const TCriticalSection& CritSecObj;
|
|
#elif defined( __OS2__ )
|
|
TMutex::Lock Lck;
|
|
#endif
|
|
};
|
|
|
|
friend Lock;
|
|
|
|
private:
|
|
|
|
#if defined( __WIN32__ )
|
|
CRITICAL_SECTION CritSec;
|
|
#elif defined( __OS2__ )
|
|
TMutex CritSec;
|
|
#endif
|
|
|
|
TCriticalSection( const TCriticalSection& );
|
|
const TCriticalSection& operator = ( const TCriticalSection& );
|
|
|
|
};
|
|
|
|
|
|
#if defined( __WIN32__ )
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TCriticalSection constructor
|
|
//
|
|
// WIN32
|
|
//
|
|
// Use system call to initialize the CRITICAL_SECTION object.
|
|
//
|
|
|
|
inline TCriticalSection::TCriticalSection()
|
|
{
|
|
::InitializeCriticalSection(CONST_CAST(CRITICAL_SECTION *,&CritSec));
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TCriticalSection destructor
|
|
//
|
|
// WIN32
|
|
//
|
|
// Use system call to destroy the CRITICAL_SECTION object.
|
|
//
|
|
|
|
inline TCriticalSection::~TCriticalSection()
|
|
{
|
|
::DeleteCriticalSection(CONST_CAST(CRITICAL_SECTION *,&CritSec));
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TCriticalSection::Lock constructor
|
|
//
|
|
// WIN32
|
|
//
|
|
// Use system call to lock the CRITICAL_SECTION object.
|
|
//
|
|
|
|
inline TCriticalSection::Lock::Lock( const TCriticalSection& sec ) :
|
|
CritSecObj(sec)
|
|
{
|
|
::EnterCriticalSection(CONST_CAST(CRITICAL_SECTION *,&CritSecObj.CritSec));
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TCriticalSection::Lock destructor
|
|
//
|
|
// WIN32
|
|
//
|
|
// Use system call to unlock the CRITICAL_SECTION object.
|
|
//
|
|
|
|
inline TCriticalSection::Lock::~Lock()
|
|
{
|
|
::LeaveCriticalSection(CONST_CAST(CRITICAL_SECTION *,&CritSecObj.CritSec));
|
|
}
|
|
|
|
#elif defined( __OS2__ )
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TCriticalSection constructor
|
|
//
|
|
// OS2
|
|
//
|
|
// Compiler takes care of constructing the TMutex data object.
|
|
//
|
|
|
|
inline TCriticalSection::TCriticalSection()
|
|
{
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TCriticalSection destructor
|
|
//
|
|
// OS2
|
|
//
|
|
// Compiler takes care of destroying the TMutex data object.
|
|
//
|
|
|
|
inline TCriticalSection::~TCriticalSection()
|
|
{
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TCriticalSection::Lock constructor
|
|
//
|
|
// OS2
|
|
//
|
|
// Construct the TMutex::Lock object to lock the
|
|
// specified TCriticalSection object.
|
|
//
|
|
|
|
inline TCriticalSection::Lock::Lock( const TCriticalSection& sec ) :
|
|
Lck(sec.CritSec)
|
|
{
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TCriticalSection::Lock destructor
|
|
//
|
|
// OS2
|
|
//
|
|
// Compiler takes care of destroying the TMutex::Lock data
|
|
// object, which releases the lock.
|
|
//
|
|
|
|
inline TCriticalSection::Lock::~Lock()
|
|
{
|
|
}
|
|
|
|
#endif
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
/* */
|
|
/* class TSync; */
|
|
/* class TSync::Lock; */
|
|
/* */
|
|
/* TSync provides a system-independent interface to build classes */
|
|
/* that act like monitors, i.e., classes in which only one member */
|
|
/* can execute on a particular instance at any one time. TSync uses */
|
|
/* TCriticalSection, so it is portable to all platforms that */
|
|
/* TCriticalSection has been ported to. */
|
|
/* */
|
|
/* TSync Public Interface */
|
|
/* ------------------------- */
|
|
/* */
|
|
/* None. TSync can only be a base class. */
|
|
/* */
|
|
/* TSync Protected Interface */
|
|
/* ---------------------------- */
|
|
/* */
|
|
/* TSync( const TSync& ); */
|
|
/* Copy constructor. Does not copy the */
|
|
/* TCriticalSection object. */
|
|
/* */
|
|
/* const TSync& operator = ( const TSync& ); */
|
|
/* Assignment operator. Does not copy the */
|
|
/* TCriticalSection object. */
|
|
/* */
|
|
/* class Lock; Handles locking and unlocking of member */
|
|
/* functions. */
|
|
/* */
|
|
/* Example */
|
|
/* ------- */
|
|
/* */
|
|
/* */
|
|
/* class ThreadSafe : private TSync */
|
|
/* { */
|
|
/* public: */
|
|
/* void f(); */
|
|
/* void g(); */
|
|
/* private: */
|
|
/* int i; */
|
|
/* }; */
|
|
/* */
|
|
/* void ThreadSafe::f() */
|
|
/* { */
|
|
/* Lock lock(this); */
|
|
/* if( i == 2 ) */
|
|
/* i = 3; */
|
|
/* } */
|
|
/* */
|
|
/* void ThreadSafe::g() */
|
|
/* { */
|
|
/* Lock lock(this); */
|
|
/* if( i == 3 ) */
|
|
/* i = 2; */
|
|
/* } */
|
|
/* */
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
class TSync
|
|
{
|
|
|
|
protected:
|
|
|
|
TSync();
|
|
TSync( const TSync& );
|
|
const TSync& operator = ( const TSync& );
|
|
|
|
class Lock : private TCriticalSection::Lock
|
|
{
|
|
public:
|
|
Lock( const TSync * );
|
|
private:
|
|
static const TCriticalSection& GetRef( const TSync * );
|
|
};
|
|
|
|
friend Lock;
|
|
|
|
private:
|
|
|
|
TCriticalSection CritSec;
|
|
|
|
};
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TSync constructors
|
|
//
|
|
// Copy constructor does not copy the TCriticalSection object,
|
|
// since the new object is not being used in any of its own
|
|
// member functions. This means that the new object must start
|
|
// in an unlocked state.
|
|
//
|
|
|
|
inline TSync::TSync()
|
|
{
|
|
}
|
|
|
|
inline TSync::TSync( const TSync& )
|
|
{
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TSync assignment operator
|
|
//
|
|
// Does not copy the TCriticalSection object, since the new
|
|
// object is not being used in any of its own member functions.
|
|
// This means that the new object must start in an unlocked state.
|
|
//
|
|
|
|
inline const TSync& TSync::operator = ( const TSync& )
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TSync::Lock constructor
|
|
//
|
|
// Locks the TCriticalSection object in the TSync object.
|
|
//
|
|
|
|
inline TSync::Lock::Lock( const TSync *sync ) :
|
|
TCriticalSection::Lock(GetRef(sync))
|
|
{
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TSync::Lock::GetRef()
|
|
//
|
|
// Returns a reference to the TCriticalSection object contained
|
|
// in the TSync object.
|
|
//
|
|
// In the diagnostic version, checks for a null pointer.
|
|
//
|
|
|
|
inline const TCriticalSection& TSync::Lock::GetRef( const TSync *sync )
|
|
{
|
|
CHECK( sync != 0 );
|
|
return sync->CritSec;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
/* */
|
|
/* template <class T> class TStaticSync; */
|
|
/* template <class T> class TStaticSync::Lock; */
|
|
/* */
|
|
/* TStaticSync provides a system-independent interface to build sets */
|
|
/* of classes that act somewhat like monitors, i.e., classes in which */
|
|
/* only one member function can execute at any one time regardless of */
|
|
/* which instance it is being called on. TStaticSync uses */
|
|
/* TCriticalSection, so it is portable to all platforms that */
|
|
/* TCriticalSection has been ported to. */
|
|
/* */
|
|
/* TStaticSync Public Interface */
|
|
/* ------------------------- */
|
|
/* */
|
|
/* None. TStaticSync can only be a base class. */
|
|
/* */
|
|
/* TStaticSync Protected Interface */
|
|
/* ---------------------------- */
|
|
/* */
|
|
/* TStaticSync<T>( const TStaticSync<T>& ); */
|
|
/* Copy constructor. Does not copy the */
|
|
/* TCriticalSection object. */
|
|
/* */
|
|
/* const TStaticSync<T>& operator = ( const TStaticSync<T>& ); */
|
|
/* Assignment operator. Does not copy the */
|
|
/* TCriticalSection object. */
|
|
/* */
|
|
/* class Lock; Handles locking and unlocking of member */
|
|
/* functions. */
|
|
/* */
|
|
/* Example */
|
|
/* ------- */
|
|
/* */
|
|
/* */
|
|
/* class ThreadSafe : private TStaticSync<ThreadSafe> */
|
|
/* { */
|
|
/* public: */
|
|
/* void f(); */
|
|
/* void g(); */
|
|
/* private: */
|
|
/* static int i; */
|
|
/* }; */
|
|
/* */
|
|
/* void ThreadSafe::f() */
|
|
/* { */
|
|
/* Lock lock; */
|
|
/* if( i == 2 ) */
|
|
/* i = 3; */
|
|
/* } */
|
|
/* */
|
|
/* void ThreadSafe::g() */
|
|
/* { */
|
|
/* Lock lock; */
|
|
/* if( i == 3 ) */
|
|
/* i = 2; */
|
|
/* } */
|
|
/* */
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
template <class T> class TStaticSync
|
|
{
|
|
|
|
protected:
|
|
|
|
TStaticSync();
|
|
TStaticSync( const TStaticSync<T>& );
|
|
const TStaticSync<T>& operator = ( const TStaticSync<T>& );
|
|
~TStaticSync();
|
|
|
|
class Lock : private TCriticalSection::Lock
|
|
{
|
|
public:
|
|
Lock() : TCriticalSection::Lock(*TStaticSync<T>::CritSec) {}
|
|
};
|
|
|
|
friend Lock;
|
|
|
|
private:
|
|
|
|
static TCriticalSection *CritSec;
|
|
static unsigned long Count;
|
|
|
|
};
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TStaticSync<T>::CritSec
|
|
// TStaticSync<T>::Count
|
|
//
|
|
// Instantiate the data members.
|
|
//
|
|
|
|
template <class T> TCriticalSection *TStaticSync<T>::CritSec;
|
|
template <class T> unsigned long TStaticSync<T>::Count;
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TStaticSync<T> constructor
|
|
//
|
|
// If this is the first TStaticSync<T> object to be constructed,
|
|
// create the semaphore.
|
|
//
|
|
// The copy constructor only has to increment the count, since
|
|
// there will already be at least one TStaticSync<T> object,
|
|
// namely, the one being copied.
|
|
//
|
|
|
|
template <class T> inline TStaticSync<T>::TStaticSync()
|
|
{
|
|
if( Count++ == 0 )
|
|
CritSec = new TCriticalSection;
|
|
}
|
|
|
|
template <class T>
|
|
inline TStaticSync<T>::TStaticSync( const TStaticSync<T>& )
|
|
{
|
|
Count++;
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TStaticSync<T> assignment operator
|
|
//
|
|
|
|
template <class T>
|
|
inline const TStaticSync<T>& TStaticSync<T>::operator = ( const TStaticSync<T>& )
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TStaticSync<T> destructor
|
|
//
|
|
// If this is the only remaining TStaticSync<T> object,
|
|
// destroy the semaphore.
|
|
//
|
|
|
|
template <class T> inline TStaticSync<T>::~TStaticSync()
|
|
{
|
|
if( --Count == 0 )
|
|
delete CritSec;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
/* */
|
|
/* class TThread; */
|
|
/* */
|
|
/* TThread provides a system-independent interface to threads. With */
|
|
/* suitable underlying implementations the same code can be used under */
|
|
/* OS/2 and Windows NT. */
|
|
/* */
|
|
/* TThread Public Interface */
|
|
/* ------------------------ */
|
|
/* */
|
|
/* Start(); Begins execution of the thread. Returns */
|
|
/* the handle of the thread. */
|
|
/* */
|
|
/* Suspend(); Suspends execution of the thread. */
|
|
/* Resume(); Resumes execution of a suspended thread. */
|
|
/* */
|
|
/* Terminate(); Sets an internal flag that indicates */
|
|
/* that the thread should exit. The */
|
|
/* derived class can check the state of */
|
|
/* this flag by calling ShouldTerminate(). */
|
|
/* */
|
|
/* WaitForExit( unsigned long timeout = NoLimit ); */
|
|
/* Blocks the calling thread until the */
|
|
/* internal thread exits or until the time */
|
|
/* specified by timeout, in milliseconds, */
|
|
/* expires. A timeout of NoLimit says to */
|
|
/* wait indefinitely. */
|
|
/* */
|
|
/* TerminateAndWait( unsigned long timeout = NoLimit ); */
|
|
/* Combines the behavior of Terminate() and */
|
|
/* WaitForExit(). Sets an internal flag that */
|
|
/* indicates that the thread should exit */
|
|
/* and blocks the calling thread until the */
|
|
/* internal thread exits or until the time */
|
|
/* specified by timeout, in milliseconds, */
|
|
/* expires. A timeout of NoLimit says to */
|
|
/* wait indefinitely. */
|
|
/* */
|
|
/* GetStatus(); Gets the current status of the thread. */
|
|
/* See TThread::Status for possible values. */
|
|
/* */
|
|
/* GetPriority(); Gets the priority of the thread. */
|
|
/* SetPriority(); Sets the priority of the thread. */
|
|
/* */
|
|
/* enum Status; Identifies the states that the class */
|
|
/* can be in. */
|
|
/* */
|
|
/* Created The class has been created but the */
|
|
/* thread has not been started. */
|
|
/* Running The thread is running. */
|
|
/* */
|
|
/* Suspended The thread has been suspended. */
|
|
/* */
|
|
/* Finished The thread has finished execution. */
|
|
/* */
|
|
/* Invalid The object is invalid. Currently this */
|
|
/* happens only when the operating system */
|
|
/* is unable to start the thread. */
|
|
/* */
|
|
/* class ThreadError; The error class that defines the objects */
|
|
/* that are thrown when an error occurs. */
|
|
/* */
|
|
/* TThread::ThreadError Public Interface */
|
|
/* ------------------------------------- */
|
|
/* */
|
|
/* enum ErrorType; Identifies the type of error that */
|
|
/* occurred. */
|
|
/* */
|
|
/* SuspendBeforeRun The user called Suspend() on an object */
|
|
/* before calling Start(). */
|
|
/* */
|
|
/* ResumeBeforeRun The user called Resume() on an object */
|
|
/* before calling Start(). */
|
|
/* */
|
|
/* ResumeDuringRun The user called Resume() on a thread that */
|
|
/* was not Suspended. */
|
|
/* */
|
|
/* SuspendAfterExit The user called Suspend() on an object */
|
|
/* whose thread had already exited. */
|
|
/* */
|
|
/* ResumeAfterExit The user called Resume() on an object */
|
|
/* whose thread had already exited. */
|
|
/* */
|
|
/* CreationFailure The operating system was unable to create */
|
|
/* the thread. */
|
|
/* */
|
|
/* DestroyBeforeExit The object's destructor was invoked */
|
|
/* its thread had exited. */
|
|
/* */
|
|
/* AssignError An attempt was made to assign to an */
|
|
/* object that was not in either the */
|
|
/* Created or the Finished state. */
|
|
/* */
|
|
/* ErrorType GetErrorType() const; */
|
|
/* Returns a code indicating the type of */
|
|
/* error that occurred. */
|
|
/* */
|
|
/* string why(); Returns a string that describes the */
|
|
/* error. Inherited from xmsg. */
|
|
/* */
|
|
/* TThread Protected Interface */
|
|
/* --------------------------- */
|
|
/* */
|
|
/* TThread(); Creates an object of type TThread. */
|
|
/* virtual ~TThread(); Destroys the object. */
|
|
/* */
|
|
/* const TThread& operator = ( const TThread& ); */
|
|
/* The target object must be in either the */
|
|
/* Created state or the Finished state. If */
|
|
/* so, puts the object into the Created */
|
|
/* state. If the object is not in either the */
|
|
/* Created state or the Finished state it */
|
|
/* is an error and an exception will be */
|
|
/* thrown. */
|
|
/* */
|
|
/* TThread( const TThread& ); */
|
|
/* Pts the object into the Created */
|
|
/* state, just like the default constructor. */
|
|
/* Does not copy any of the internal details */
|
|
/* of the thread being copied. */
|
|
/* */
|
|
/* virtual unsigned long Run() = 0; */
|
|
/* The function that does the work. Calling */
|
|
/* Start() creates a thread that begins */
|
|
/* executing Run() with the 'this' pointer */
|
|
/* pointing to the TThread-based object. */
|
|
/* */
|
|
/* int ShouldTerminate() const; */
|
|
/* Returns a non-zero value to indicate */
|
|
/* that Terminate() or TerminateAndWait() */
|
|
/* has been called. If this capability is */
|
|
/* being used, the thread should call */
|
|
/* ShouldTerminate() regularly, and if it */
|
|
/* returns a non-zero value the thread */
|
|
/* finish its processing and exit. */
|
|
/* */
|
|
/* Example */
|
|
/* ------- */
|
|
/* */
|
|
/* class TimerThread : public TThread */
|
|
/* { */
|
|
/* public: */
|
|
/* TimerThread() : Count(0) {} */
|
|
/* private: */
|
|
/* unsigned long Run(); */
|
|
/* int Count; */
|
|
/* }; */
|
|
/* */
|
|
/* unsigned long TimerThread::Run() */
|
|
/* { */
|
|
/* // loop 10 times */
|
|
/* while( Count++ < 10 ) */
|
|
/* { */
|
|
/* Sleep(1000); // delay 1 second */
|
|
/* cout << "Iteration " << Count << endl; */
|
|
/* } */
|
|
/* return 0L; */
|
|
/* } */
|
|
/* */
|
|
/* int main() */
|
|
/* { */
|
|
/* TimerThread timer; */
|
|
/* timer.Start(); */
|
|
/* Sleep( 20000 ); // delay 20 seconds */
|
|
/* return 0; */
|
|
/* } */
|
|
/* */
|
|
/* Internal States */
|
|
/* --------------- */
|
|
/* */
|
|
/* Created : the object has been created but its thread has not been */
|
|
/* started. The only valid transition from this state is */
|
|
/* to Running, which happens on a call to Start(). In */
|
|
/* particular, a call to Suspend() or Resume() when the */
|
|
/* object is in this state is an error and will throw an */
|
|
/* exception. */
|
|
/* */
|
|
/* Running: the thread has been started successfully. There are two */
|
|
/* transitions from this state: */
|
|
/* */
|
|
/* When the user calls Suspend() the object moves into */
|
|
/* the Suspended state. */
|
|
/* */
|
|
/* When the thread exits the object moves into the */
|
|
/* Finished state. */
|
|
/* */
|
|
/* Calling Resume() on an object that is in the Running */
|
|
/* state is an error and will throw an exception. */
|
|
/* */
|
|
/* Suspended: the thread has been suspended by the user. Subsequent */
|
|
/* calls to Suspend() nest, so there must be as many calls */
|
|
/* to Resume() as there were to Suspend() before the thread */
|
|
/* actually resumes execution. */
|
|
/* */
|
|
/* Finished: the thread has finished executing. There are no valid */
|
|
/* transitions out of this state. This is the only state */
|
|
/* from which it is legal to invoke the destructor for the */
|
|
/* object. Invoking the destructor when the object is in */
|
|
/* any other state is an error and will throw an exception. */
|
|
/* */
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
class _BIDSCLASS TThread
|
|
{
|
|
|
|
public:
|
|
|
|
#if defined( __WIN32__ )
|
|
// Windows NT
|
|
enum { NoLimit = -1 };
|
|
typedef HANDLE THandle;
|
|
#elif defined( __OS2__ )
|
|
// OS/2
|
|
enum { NoLimit = DCWW_WAIT };
|
|
typedef TID THandle;
|
|
#endif
|
|
|
|
enum Status { Created, Running, Suspended, Finished, Invalid };
|
|
|
|
THandle Start();
|
|
unsigned long Suspend();
|
|
unsigned long Resume();
|
|
void Terminate();
|
|
unsigned long WaitForExit( unsigned long timeout = NoLimit );
|
|
unsigned long TerminateAndWait( unsigned long timeout = NoLimit );
|
|
|
|
Status GetStatus() const;
|
|
|
|
int GetPriority() const;
|
|
int SetPriority(int);
|
|
|
|
class ThreadError : public xmsg
|
|
{
|
|
friend TThread;
|
|
public:
|
|
enum ErrorType
|
|
{
|
|
SuspendBeforeRun,
|
|
ResumeBeforeRun,
|
|
ResumeDuringRun,
|
|
SuspendAfterExit,
|
|
ResumeAfterExit,
|
|
CreationFailure,
|
|
DestroyBeforeExit,
|
|
AssignError
|
|
};
|
|
ErrorType GetErrorType() const;
|
|
private:
|
|
ThreadError(ErrorType type);
|
|
static string MakeString(ErrorType type );
|
|
ErrorType Type;
|
|
};
|
|
|
|
protected:
|
|
|
|
TThread();
|
|
|
|
// Copying a thread puts the target into the Created state
|
|
TThread( const TThread& );
|
|
const TThread& operator = ( const TThread& );
|
|
|
|
virtual ~TThread();
|
|
|
|
int ShouldTerminate() const;
|
|
|
|
private:
|
|
|
|
virtual unsigned long Run() = 0;
|
|
|
|
Status CheckStatus() const;
|
|
|
|
THandle Handle;
|
|
#if defined( __MT__ )
|
|
static void _USERENTRY Execute( void *thread );
|
|
#elif defined( __WIN32__ )
|
|
static unsigned long _stdcall Execute( void *thread );
|
|
#else
|
|
static void __stdcall Execute( unsigned long );
|
|
#endif
|
|
#if defined( __WIN32__ )
|
|
DWORD ThreadId;
|
|
#else
|
|
ULONG Priority;
|
|
#endif
|
|
mutable Status Stat;
|
|
|
|
int TerminationRequested;
|
|
|
|
};
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TThread::GetStatus()
|
|
//
|
|
// If the thread is marked as Running it may have terminated
|
|
// without our knowing it, so we have to check.
|
|
//
|
|
|
|
#if defined( BI_NO_MUTABLE )
|
|
inline TThread::Status TThread::GetStatus() const
|
|
{
|
|
if( Stat == Running )
|
|
CONST_CAST(TThread *,this)->Stat = CheckStatus();
|
|
return Stat;
|
|
}
|
|
#else
|
|
inline TThread::Status TThread::GetStatus() const
|
|
{
|
|
if( Stat == Running )
|
|
Stat = CheckStatus();
|
|
return Stat;
|
|
}
|
|
#endif
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TThread::GetPriority()
|
|
//
|
|
// Direct OS call under WIN32. Return stored value under OS/2.
|
|
//
|
|
|
|
inline int TThread::GetPriority() const
|
|
{
|
|
#if defined( __WIN32__ )
|
|
return ::GetThreadPriority(Handle);
|
|
#else
|
|
return Priority;
|
|
#endif
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TThread::ShouldTerminate()
|
|
//
|
|
inline int TThread::ShouldTerminate() const
|
|
{
|
|
return TerminationRequested;
|
|
}
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// TThread::ThreadError::GetErrorType()
|
|
//
|
|
|
|
inline TThread::ThreadError::ErrorType TThread::ThreadError::GetErrorType() const
|
|
{
|
|
return Type;
|
|
}
|
|
|
|
#if defined( BI_CLASSLIB_NO_po )
|
|
#pragma option -po.
|
|
#endif
|
|
|
|
#endif // __THREAD_H
|
|
|
|
|