2009年12月21日 星期一

CuWinThread - Represents a thread of execution within an application.

// 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;
}



1 則留言:

  1. 許多年前從MFC裡將這個Thread類別移出 CObject, 並且將跟windows 相關的東西都刪掉, 還是覺得寫的真好! 這些年來, 都沒不想改動這個類別!

    回覆刪除