⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 threads_w32.cpp

📁 美国COPLEY驱动器,程序开发工具之一.
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/************************************************************/
/*                                                          */
/*  Copley Motion Libraries                                 */
/*                                                          */
/*  Author: Stephen Glow                                    */
/*                                                          */
/*  Copyright (c) 2002-2005 Copley Controls Corp.           */
/*                          http://www.copleycontrols.com   */
/*                                                          */
/************************************************************/


#include <windows.h>
#include <process.h>
#include "CML.h"

CML_NAMESPACE_USE();

/* local data */
DWORD tlsIndex = TLS_OUT_OF_INDEXES;
Mutex globalThreadMutex;

/* local classes */
struct WinThreadData
{
   // Pointer to the thread object
   Thread *thread;

   // Mutex used to synchronize access to the thread specific data
   Mutex mtx;

   // True if the thread is running.
   bool running;

   // This event is signaled when the thread is destroyed
   HANDLE killEvent;

   // The thread signals this event when it exits.
   HANDLE exitEvent;

   // The thread's handle
   HANDLE threadHandle;

   WinThreadData( Thread *t )
   {
      thread = t;
      running = false;

      // Create events used to manage the thread
      killEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
      exitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
   }

   ~WinThreadData(){
      if( killEvent ) CloseHandle( killEvent );
      if( exitEvent ) CloseHandle( exitEvent );
   }
};

/**************************************************
* This class is used to terminate the running thread.
* It's thrown as an exception, and caught in the 
* thread starter stub.  This allows my stack to 
* unwind properly in a thread that is stopped.
**************************************************/
class ThreadExitException
{
};

/* local functions */
static void __cdecl ThreadStarter( void *arg );
static WinThreadData *GetThreadData( void );
static void KillThread( WinThreadData *tData );

/* global functions */
const Error *WaitOnWindowsObject( HANDLE hndl, int32 timeout );

/***************************************************************************/
/**
Default constructor for a new thread object.  For the pthreads version of
this class the default constructor doesn't do anything.
*/
/***************************************************************************/
Thread::Thread( void )
{
   priority = 5;
   WinThreadData *tData = new WinThreadData( this );

   // Make sure the events were created successfully
   if( !tData->killEvent || !tData->exitEvent )
   {
      delete tData;
      data = 0;
   }
   else
      data = tData;
}

/***************************************************************************/
/**
Destructor for a thread.  Causes the thread to be cancelled and waits for
it to finish.
*/
/***************************************************************************/
Thread::~Thread( void )
{
   // Stop the thread 
   const Error *err = stop(500);

   // If this fails I just return without deleting the thread data.
   // This really shouldn't happen!
   if( err )
   {
      cml.Error( "Error stopping thread in destructor: %s\n", err->toString() );
      return;
   }

   // Lock the mutex to make sure the thread really stopped
   WinThreadData *tData = (WinThreadData*)data;
   tData->mtx.Lock();

   delete data;
}

/***************************************************************************/
/**
Set the threads priority.  The priority must be specified in the range 0 
(lowest priority) to 9 (highest priority).  The default thread priority 
is 5 and this will be used if the priority is not explicitely set.

This funciton must be called before the thread is started.  Calling it
after the thread has already started will have no effect.

@param pri The thread's priority, in the range 0 to 9.
@return A valid error object.
*/
/***************************************************************************/
const Error *Thread::setPriority( int pri )
{
   if( pri < 0 || pri > 9 )
      return &ThreadError::BadParam;

   priority = pri;

   return 0;
}

/***************************************************************************/
/**
Start this thread.  The thread's virtual run() function will be called when
the thread has started.
*/
/***************************************************************************/
const Error *Thread::start( void )
{
   HANDLE h;
   const Error *err = 0;

   // Make sure my local data was properly allocated by the 
   // constructor.
   if( !data ) return &ThreadError::Alloc;

   // Allocate a single slot of thread local storage if not already done.
   globalThreadMutex.Lock();
   if( tlsIndex == TLS_OUT_OF_INDEXES )
      tlsIndex = TlsAlloc();

   if( tlsIndex == TLS_OUT_OF_INDEXES )
      err = &ThreadError::Alloc;
   globalThreadMutex.Unlock();
   if( err ) return err;

   WinThreadData *tData = (WinThreadData*)data;
   tData->mtx.Lock();

   // Make sure the thread isn't already started
   if( tData->running )
      err = &ThreadError::Running;

   else if( (h = (HANDLE)_beginthread( ThreadStarter, 0, tData )) == (HANDLE)-1 )
      err = &ThreadError::Start;

   else
   {
      int pri;
      switch( priority )
      {
	 case 0:  pri = THREAD_PRIORITY_IDLE;          break;
	 case 1:  pri = THREAD_PRIORITY_LOWEST;        break;
	 case 2:  pri = THREAD_PRIORITY_LOWEST;        break;
	 case 3:  pri = THREAD_PRIORITY_BELOW_NORMAL;  break;
	 case 4:  pri = THREAD_PRIORITY_BELOW_NORMAL;  break;
	 case 5:  pri = THREAD_PRIORITY_NORMAL;        break;
	 case 6:  pri = THREAD_PRIORITY_ABOVE_NORMAL;  break;
	 case 7:  pri = THREAD_PRIORITY_ABOVE_NORMAL;  break;
	 case 8:  pri = THREAD_PRIORITY_HIGHEST;       break;
	 case 9:  pri = THREAD_PRIORITY_TIME_CRITICAL; break;
	 default: pri = THREAD_PRIORITY_NORMAL;        break;
      }

      SetThreadPriority( h, pri );
      tData->running = true;
   }

   tData->mtx.Unlock();
   return err;
}

/***************************************************************************/
/**
Stop the thread.  The threads stack should unwind properly when stopped.
Note, I believe that there are race conditions if the thread returns and 
another thread trys to stop it at the same time.  Also make sure that 
things are properly cleaned up when the thread returns.
I may need to add a mutex to the thread object to help manage this.
*/
/***************************************************************************/
const Error *Thread::stop( int32 timeout )
{
   cml.Debug( "Stopping thread %p\n", this );

   if( !data ) return &ThreadError::Alloc;

   WinThreadData *tData = (WinThreadData *)data;
   tData->mtx.Lock();

   // Just return if the thread wasn't running
   if( !tData->running )
   {
      tData->mtx.Unlock();
      return 0;
   }
   tData->mtx.Unlock();

   // If this happens to by the running thread, then throw an exception.
   // This will cause my stack to unwind until the exception is caught
   // by the starter function.
   if( tData == GetThreadData() )
   {
      cml.Debug( "Thread %p is running thread, exiting\n", this );
      throw ThreadExitException();
   }

   // Otherwise, signal the thread to kill itself
   SetEvent( tData->killEvent );

   if( !timeout ) return 0;

   // Wait for the thread to exit
   DWORD ret = WaitForSingleObject( tData->exitEvent, timeout );

   switch( ret )
   {
      case WAIT_OBJECT_0:
	 cml.Debug( "Thread %p successfully stopped\n", this );
	 break;

      case WAIT_TIMEOUT:
	 cml.Warn( "Thread %p, timeout waiting for exit\n", this );
	 return &ThreadError::Timeout;

      default:
	 cml.Warn( "Thread %p, error %d waiting for exit\n", this, ret );
	 break;
   }

   return 0;
}

/***************************************************************************/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -