📄 threads_w32.cpp
字号:
/**
Thread starting function. This static function is called when a new thread
is started. It calls Thread::run()
*/
/***************************************************************************/
static void __cdecl ThreadStarter( void *arg )
{
WinThreadData *tData = (WinThreadData *)arg;
TlsSetValue( tlsIndex, tData );
try
{
tData->thread->run();
}
catch( ThreadExitException )
{
}
// Set an event used to indicate that this thread is exited
tData->mtx.Lock();
SetEvent( tData->exitEvent );
tData->running = false;
tData->mtx.Unlock();
return;
}
/***************************************************************************/
/**
Put the thread to sleep for a specified amount of time.
@param timeout The time to sleep in milliseconds. If <0 the thread will
sleep forever.
*/
/***************************************************************************/
const Error *Thread::sleep( int32 timeout )
{
if( !timeout ) return 0;
// Create a semaphore that no-one will ever post to
// and wait on that with a timeout
Semaphore sem = 0;
const Error *err = sem.Get( timeout );
// Convert timeout errors to no error since
// that's what we expect to see.
if( err == &ThreadError::Timeout )
err = 0;
return err;
}
/***************************************************************************/
/**
Return a pointer to the running thread's WinThreadData structure.
@return A pointer to the structure, or NULL if the running thread wasn't
created using the Thread object.
*/
/***************************************************************************/
static WinThreadData *GetThreadData( void )
{
if( tlsIndex == TLS_OUT_OF_INDEXES ) return 0;
return (WinThreadData *)TlsGetValue( tlsIndex );
}
/***************************************************************************/
/**
Create a new mutex object with default attributes.
*/
/***************************************************************************/
Mutex::Mutex( void )
{
data = CreateMutex( NULL, FALSE, NULL );
}
/***************************************************************************/
/**
Create a new mutex object with default attributes.
*/
/***************************************************************************/
Mutex::~Mutex()
{
if( data )
{
CloseHandle( (HANDLE)data );
}
}
/***************************************************************************/
/**
Lock this mutex
*/
/***************************************************************************/
const Error *Mutex::Lock( void )
{
if( !data ) return &ThreadError::Alloc;
return WaitOnWindowsObject( (HANDLE)data, -1 );
}
/***************************************************************************/
/**
Unlock the mutex
*/
/***************************************************************************/
const Error *Mutex::Unlock( void )
{
if( !data ) return &ThreadError::Alloc;
if( !ReleaseMutex( (HANDLE)data ) )
cml.Error( "ReleaseMutex failed with error %ld\n", GetLastError() );
return 0;
}
/***************************************************************************/
/**
Default constructore for a semaphore object. Initializes the semaphore to
it's default attributes.
*/
/***************************************************************************/
Semaphore::Semaphore( int32 count )
{
data = CreateSemaphore( NULL, count, 0x7fffffff, NULL );
}
/***************************************************************************/
/**
Semaphore destructor
*/
/***************************************************************************/
Semaphore::~Semaphore()
{
if( data )
CloseHandle( (HANDLE)data );
}
/***************************************************************************/
/**
Get the semaphore with an optional timeout. An error is returned if the
timeout expires before the semaphore is acquired.
@param timeout The timeout in milliseconds. Any negative value will cause
the thread to wait indefinitely.
@return An error code indicating success or failure.
*/
/***************************************************************************/
const Error *Semaphore::Get( int32 timeout )
{
if( !data ) return &ThreadError::Alloc;
return WaitOnWindowsObject( (HANDLE)data, timeout );
}
/***************************************************************************/
/**
Post to the semaphore.
*/
/***************************************************************************/
const Error *Semaphore::Put( void )
{
if( !data ) return &ThreadError::Alloc;
if( !ReleaseSemaphore( (HANDLE)data, 1, NULL ) )
return 0;
return &ThreadError::General;
}
/***************************************************************************/
/**
Kill the running thread.
*/
/***************************************************************************/
static void KillThread( WinThreadData *tData )
{
throw ThreadExitException();
}
/***************************************************************************/
/**
Wait for some Windows object (semaphore, mutex, event, etc) with a timeout.
This function should be used for Thread objects that need to wait on
Windows objects rather then the standard WaitOnSingleObject call. The
reason is that this function allows the thread to be destroyed using Thread::stop.
Normally, windows objects aren't directly used anyway, but it's sometimes
required when writing the low level CAN driver for example.
@param hndl The handle to a windows object
@param timeout A timeout value (milliseconds). Use -1 for infinite.
@return A pointer to an error object, or NULL on success
*/
/***************************************************************************/
const Error *WaitOnWindowsObject( HANDLE hndl, int32 timeout )
{
DWORD ret;
if( timeout < 0 ) timeout = INFINITE;
// See if the calling thread was created using a Thread object.
// If so, I will watch to make sure it isn't killed.
WinThreadData *tData = GetThreadData();
// If that returned NULL, then this thread isn't part of a Thread object.
// In that case, just wait on the semaphore
if( !tData )
{
ret = WaitForSingleObject( hndl, timeout );
}
// If this is part of a Thread object, then wait for either the semaphore
// or the kill event. If the kill event is set, then I'll exit the thread
// gracefully.
else
{
HANDLE h[2];
h[0] = hndl;
h[1] = tData->killEvent;
ret = WaitForMultipleObjects( 2, h, FALSE, timeout );
}
switch( ret )
{
case WAIT_OBJECT_0:
return 0;
case WAIT_OBJECT_0+1:
KillThread( tData );
return 0;
case WAIT_TIMEOUT:
// The wait timed out. If a non-zero timeout was specified
// then try another wait with a zero timeout. Windows seems
// to generate false timeout conditions fairly often.
if( (timeout > 0) && (WaitForSingleObject( hndl, 0 ) == WAIT_OBJECT_0) )
return 0;
return &ThreadError::Timeout;
default:
return &ThreadError::General;
}
}
/***************************************************************************/
/**
This function can be used by a thread to check to see if it has been stopped.
Normally, the thread is automatically stopped when it tries to get a mutex
or semaphore, but this can be used to stop a thread that is doing something
else for a long time.
It's presently just used in some CanInterface drivers for those drivers that
don't allow me to stop the thread in a more direct way.
*/
/***************************************************************************/
void CheckWindowsThreadStop( void )
{
// Find my thread data.
WinThreadData *tData = GetThreadData();
// If that returned NULL, then I'm not part of a Thread object.
// I can just return.
if( !tData ) return;
// Test the kill event for this thread. Return if it's not signaled.
if( WaitForSingleObject( tData->killEvent, 0 ) != WAIT_OBJECT_0 )
return;
// End it all!
KillThread( tData );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -