// Represents a thread of execution within an application.
// CuWinThread.h
typedef UINT (__cdecl *_THREADPROC)(LPVOID);
// global helpers for threads
class CuWinThread;
CuWinThread* _BeginThread(_THREADPROC pfnThreadProc, LPVOID pParam,
int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0,
DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);
class CuWinThread
{
public:
BOOL CreateThread(DWORD dwCreateFlags = 0, UINT nStackSize = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);
// only valid while running
HANDLE m_hThread; // this thread's HANDLE
DWORD m_nThreadID; // this thread's ID
BOOL m_bAutoDelete; // enables 'delete this' after thread termination
LPVOID m_pThreadParams; // generic parameters passed to starting function
_THREADPROC m_pfnThreadProc;
CuWinThread();
CuWinThread(_THREADPROC pfnThreadProc, LPVOID pParam);
// Operations
DWORD SuspendThread();
DWORD ResumeThread();
BOOL SetThreadPriority(int nPriority);
// Implementation
void CommonConstruct();
virtual ~CuWinThread();
// 'delete this' only if m_bAutoDelete == TRUE
virtual void Delete();
};
inline DWORD CuWinThread::ResumeThread()
{ Assert(m_hThread != NULL, _T("CuWinThread::ResumeThread m_hThread != NULL") ); return ::ResumeThread(m_hThread); }
inline DWORD CuWinThread::SuspendThread()
{ Assert(m_hThread != NULL, _T("CuWinThread::SuspendThread m_hThread != NULL")) ; return ::SuspendThread(m_hThread); }
inline BOOL CuWinThread::SetThreadPriority(int nPriority)
{ Assert(m_hThread != NULL, _T("CuWinThread::SetThreadPriority m_hThread != NULL")); return ::SetThreadPriority(m_hThread, nPriority); }
// CuWinThread.cpp
struct _THREAD_STARTUP
{
// following are "in" parameters to thread startup
//_THREAD_STATE* pThreadState; // thread state of parent thread
CuWinThread* pThread; // CWinThread for new thread
DWORD dwCreateFlags; // thread creation flags
HANDLE hEvent; // event triggered after success/non-success
HANDLE hEvent2; // event triggered after thread is resumed
// strictly "out" -- set after hEvent is triggered
BOOL bError; // TRUE if error during startup
};
DWORD __cdecl _ThreadEntry(void* pParam)
{
_THREAD_STARTUP* pStartup = (_THREAD_STARTUP*)pParam;
Assert(pStartup != NULL, _T("_ThreadEntry::\npStartup != NULL"));
Assert(pStartup->pThread != NULL, _T("_ThreadEntry::\npStartup->pThread != NULL"));
Assert(pStartup->hEvent != NULL, _T("_ThreadEntry::\npStartup->hEvent != NULL"));
Assert(!pStartup->bError, _T("_ThreadEntry::\n!pStartup->bError"));
CuWinThread* pThread = pStartup->pThread;
// pStartup is invlaid after the following
// SetEvent (but hEvent2 is valid)
HANDLE hEvent2 = pStartup->hEvent2;
// allow the creating thread to return from CWinThread::CreateThread
Verify(::SetEvent(pStartup->hEvent), _T(""));
// wait for thread to be resumed
Verify(::WaitForSingleObject(hEvent2, INFINITE) == WAIT_OBJECT_0, _T(""));
::CloseHandle(hEvent2);
// first -- check for simple worker thread
DWORD nResult = 0;
if (pThread->m_pfnThreadProc != NULL)
{
nResult = (*pThread->m_pfnThreadProc)(pThread->m_pThreadParams);
}
pThread->Delete();
// allow C-runtime to cleanup, and exit the thread
::ExitThread(nResult);
return 0;
}
CuWinThread* _BeginThread(_THREADPROC pfnThreadProc, LPVOID pParam,
int nPriority /* = THREAD_PRIORITY_NORMAL */, UINT nStackSize /* = 0 */,
DWORD dwCreateFlags /* = 0 */, LPSECURITY_ATTRIBUTES lpSecurityAttrs /* = NULL*/ )
{
Assert(pfnThreadProc != NULL, _T(""));
CuWinThread* pThread = new CuWinThread(pfnThreadProc, pParam);
Assert(pThread != NULL , _T("_BeginThread:: pThread == NULL"));
if (!pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED, nStackSize,
lpSecurityAttrs))
{
pThread->Delete();
return NULL;
}
Verify(pThread->SetThreadPriority(nPriority) , _T(""));
if (!(dwCreateFlags & CREATE_SUSPENDED))
Verify(pThread->ResumeThread() != (DWORD)-1, _T(""));
return pThread;
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CuWinThread::CuWinThread()
{
m_pThreadParams = NULL;
m_pfnThreadProc = NULL;
CommonConstruct();
}
CuWinThread::CuWinThread(_THREADPROC pfnThreadProc, LPVOID pParam)
{
m_pThreadParams = pParam;
m_pfnThreadProc = pfnThreadProc;
CommonConstruct();
}
CuWinThread::~CuWinThread()
{
// free thread object
if (m_hThread != NULL)
CloseHandle(m_hThread);
}
void CuWinThread::CommonConstruct()
{
m_hThread = NULL;
m_nThreadID = 0;
m_bAutoDelete = TRUE;
}
void CuWinThread::Delete()
{
// delete thread if it is auto-deleting
if (m_bAutoDelete)
delete this;
}
BOOL CuWinThread::CreateThread(DWORD dwCreateFlags, UINT nStackSize, LPSECURITY_ATTRIBUTES lpSecurityAttrs)
{
Assert(m_hThread == NULL, _T("CreateThread::m_hThread == NULL")); // already created?
// setup startup structure for thread initialization
_THREAD_STARTUP startup;
memset(&startup, 0, sizeof(startup));
startup.pThread = this;
startup.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
startup.hEvent2 = ::CreateEvent(NULL, TRUE, FALSE, NULL);
startup.dwCreateFlags = dwCreateFlags;
if (startup.hEvent == NULL || startup.hEvent2 == NULL)
{
Assert(0, _T("Warning: CreateEvent failed in CWinThread::CreateThread.\n"));
//TRACE(traceAppMsg, 0, "Warning: CreateEvent failed in CWinThread::CreateThread.\n");
if (startup.hEvent != NULL)
::CloseHandle(startup.hEvent);
if (startup.hEvent2 != NULL)
::CloseHandle(startup.hEvent2);
return FALSE;
}
// create the thread (it may or may not start to run)
m_hThread = ::CreateThread(lpSecurityAttrs, nStackSize, //REVIEW
(LPTHREAD_START_ROUTINE)&_ThreadEntry, &startup, dwCreateFlags | CREATE_SUSPENDED, (PDWORD)&m_nThreadID);
if (m_hThread == NULL)
return FALSE;
// start the thread just for MFC initialization
Verify(ResumeThread() != (DWORD)-1, _T(""));
Verify(::WaitForSingleObject(startup.hEvent, INFINITE) == WAIT_OBJECT_0, _T(""));
::CloseHandle(startup.hEvent);
// if created suspended, suspend it until resume thread wakes it up
if (dwCreateFlags & CREATE_SUSPENDED)
Verify(::SuspendThread(m_hThread) != (DWORD)-1, _T(""));
// if error during startup, shut things down
if (startup.bError)
{
Verify(::WaitForSingleObject(m_hThread, INFINITE) == WAIT_OBJECT_0, _T(""));
::CloseHandle(m_hThread);
m_hThread = NULL;
::CloseHandle(startup.hEvent2);
return FALSE;
}
// allow thread to continue, once resumed (it may already be resumed)
::SetEvent(startup.hEvent2);
return TRUE;
}
2009年12月21日 星期一
CuWinThread - Represents a thread of execution within an application.
訂閱:
張貼留言 (Atom)
許多年前從MFC裡將這個Thread類別移出 CObject, 並且將跟windows 相關的東西都刪掉, 還是覺得寫的真好! 這些年來, 都沒不想改動這個類別!
回覆刪除