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