共享Windows下C++庫之線程篇

今天把平時積累的一些比較常用的庫給共享出來,一來“展現”下自己的開源精神,二來也可以發表下自己的看法。(假設你熟悉C++ tr1的組件)

共享順序

1.線程庫(線程篇、線程池篇、線程同步與本地線程存儲篇)

2.內存庫(待續…)

3.網絡庫(待續…)

 

一、線程篇(創建和管理單線程)

在Windows下,如果要在某類中創建線程使用,則有如下幾個缺點(不方便)

1. 要提供線程句柄的管理

2.要提供線程入口函數(必須爲static且具有__stdcall調用方式)

3.要有機制使線程退出(bool、Event、APC…)

4.需要在CreateThread,_beginthreadex,ATL::CreateThreadT,MFC::AfxBeginThread等等做決策

5.還沒想到~~

有上述如此之多的不方便和缺點,促使了我開發此組件。該組件有效地解決了上述問題。使用方式:

1.聲明類(需要線程的類)成員變量—>ThreadImplEx m_thread;

2.註冊線程函數(不需要爲static且__stdcall的調用方式,使用類普通成員函數即可__thiscall)—>m_thread.RegisterFunc(std::tr1::bind(….));

3.開始線程—>m_thread.Start()

4.結束線程—>m_thread.Stop();

OK!上組件代碼

#ifndef __THREAD_THREAD_HPP
#define __THREAD_THREAD_HPP


#include "../Thread.hpp"



#ifndef ATLTRY
#define ATLTRY(x) (x)
#endif // ATLTRY





namespace DataStructure
{


//-----------------------------------------------------
// CThread

template< bool t_bManaged >
class CThreadT
{
public:
HANDLE m_hThread; // Handle to thread
DWORD m_dwThreadID; // Thread ID
bool m_bSuspended; // Thread currently suspended?

CThreadT(HANDLE hThread = NULL) : m_hThread(hThread), m_dwThreadID(0), m_bSuspended(false)
{
}

~CThreadT()
{
if( t_bManaged ) Release();
}

// Operations

bool Create(LPTHREAD_START_ROUTINE pThreadProc, LPVOID pParam = NULL, int iPriority = THREAD_PRIORITY_NORMAL)
{
_ASSERTE(m_hThread==NULL);
_ASSERTE(pThreadProc);

#if defined(_MT) || defined(_DLL)
m_hThread = (HANDLE) _beginthreadex(NULL, 0, (UINT (WINAPI*)(void*)) pThreadProc, pParam, CREATE_SUSPENDED, (UINT*) &m_dwThreadID);
#else
m_hThread = ::CreateThread(NULL, 0, pThreadProc, pParam, CREATE_SUSPENDED, &m_dwThreadID);
#endif // _MT

if( m_hThread == NULL )
return FALSE;

if( iPriority != THREAD_PRIORITY_NORMAL )
{
if( !::SetThreadPriority(m_hThread, iPriority) )
{
_ASSERTE(!"Couldn't set thread priority");
}
}

return ::ResumeThread(m_hThread) != (DWORD) -1;
}

bool Release()
{
if( m_hThread == NULL )
return TRUE;
if( ::CloseHandle(m_hThread) == FALSE )
return FALSE;

m_hThread = NULL;
m_dwThreadID = 0;

return TRUE;
}

void Attach(HANDLE hThread)
{
_ASSERTE(m_hThread==NULL);
m_hThread = hThread;
}

HANDLE Detach()
{
HANDLE hThread = m_hThread;
m_hThread = NULL;

return hThread;
}

bool SetPriority(int iPriority) const
{
_ASSERTE(m_hThread);

return ::SetThreadPriority(m_hThread, iPriority);
}

int GetPriority() const
{
_ASSERTE(m_hThread);

return ::GetThreadPriority(m_hThread);
}

bool Suspend()
{
_ASSERTE(m_hThread);

if( m_bSuspended )
return TRUE;

if( ::SuspendThread(m_hThread) == (DWORD) -1 )
return FALSE;

m_bSuspended = true;

return TRUE;
}

bool Resume()
{
_ASSERTE(m_hThread);

if( !m_bSuspended )
return TRUE;

if( ::ResumeThread(m_hThread) == (DWORD) -1 )
return FALSE;

m_bSuspended = false;

return TRUE;
}

bool IsSuspended() const
{
_ASSERTE(m_hThread);

return m_bSuspended == true;
}

bool IsRunning() const
{
if( m_hThread == NULL )
return FALSE;
DWORD dwCode = 0;

::GetExitCodeThread(m_hThread, &dwCode);

return dwCode == STILL_ACTIVE;
}

bool WaitForThread(DWORD dwTimeout = INFINITE) const
{
_ASSERTE(m_hThread);

return ::WaitForSingleObject(m_hThread, dwTimeout) == WAIT_OBJECT_0;
}

bool Terminate(DWORD dwExitCode = 0) const
{
// See Q254956 why calling this could be a bad idea!
_ASSERTE(m_hThread);

return TRUE == ::TerminateThread(m_hThread, dwExitCode);
}

DWORD GetThreadID() const
{
return m_dwThreadID;
}

bool GetExitCode(DWORD* pExitCode) const
{
_ASSERTE(m_hThread);
_ASSERTE(pExitCode);

return ::GetExitCodeThread(m_hThread, pExitCode);
}

#if(WINVER >= 0x0500)

bool GetThreadTimes(LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime) const
{
_ASSERTE(m_hThread);
_ASSERTE(lpExitTime!=NULL && lpKernelTime!=NULL && lpUserTime!=NULL);

return ::GetThreadTimes(m_hThread, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime);
}

#endif // WINVER

#if(WINVER >= 0x0501)

bool SetThreadAffinityMask(DWORD dwThreadMask)
{
_ASSERTE(m_hThread);

return ::SetThreadAffinityMask(m_hThread, dwThreadMask) != 0;
}

bool SetThreadIdealProcessor(DWORD dwIdealProcessor)
{
_ASSERTE(m_hThread);

return ::SetThreadIdealProcessor(m_hThread, dwIdealProcessor) != (DWORD) -1;
}

DWORD GetThreadIdealProcessor() const
{
_ASSERTE(m_hThread);

return ::SetThreadIdealProcessor(m_hThread, MAXIMUM_PROCESSORS);
}

#endif // WINVER

operator HANDLE() const
{
return m_hThread;
}
};

typedef CThreadT CThreadHandle;
typedef CThreadT CThread;


//----------------------------------------------------------------------
// Thread Stop policy

class CThreadStopAtBool
{
public:
volatile bool m_bStopped;
CThreadStopAtBool() : m_bStopped(false) { };
bool _ClearAbort() { m_bStopped = false; return TRUE; };
bool _Abort() { m_bStopped = true; return TRUE; };
bool _IsAborted() const { return m_bStopped == true; };
};

class CThreadStopAtEvent
{
public:
HANDLE m_hStopEvent;
CThreadStopAtEvent() { m_hStopEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); };
~CThreadStopAtEvent() { ::CloseHandle(m_hStopEvent); };
BOOL _ClearAbort() { return ::ResetEvent(m_hStopEvent); };
BOOL _Abort() { return ::SetEvent(m_hStopEvent); };
bool _IsAborted() const { return ::WaitForSingleObject(m_hStopEvent, 0) != WAIT_TIMEOUT; };
};


/////////////////////////////////////////////////////////////////////////////
// CThreadImpl

template< typename T, typename TStopPolicy = CThreadStopAtBool >
class CThreadImpl
: public CThread
, public TStopPolicy
{
public:
bool m_bAutoDelete; // Thread class will delete itself upon thread exit?
bool m_bAutoCleanup; // Thread class will wait for thread completion upon scope exit?

CThreadImpl()
: m_bAutoDelete(false)
, m_bAutoCleanup(true)
{
}

~CThreadImpl()
{
if( m_bAutoCleanup )
Stop();
}

// Operations

bool Start()
{
if( !_ClearAbort() )
return FALSE;
if( !Create(ThreadProc, (LPVOID) static_cast(this)) )
return FALSE;

return TRUE;
}

void Stop()
{
if( !Abort() )
return;

WaitForThread();
Release();
}

bool Abort()
{
if( m_hThread == NULL )
return FALSE;
if( !_Abort() )
return FALSE;
if( m_bSuspended )
Resume();

return TRUE;
}

bool IsAborted() const
{
_ASSERTE(m_hThread);

return _IsAborted();
}

void SetAutoClean(bool bAutoClean = true)
{
m_bAutoCleanup = bAutoClean;
}

void SetDeleteOnExit(bool bAutoDelete = true)
{
m_bAutoDelete = bAutoDelete;
m_bAutoCleanup = !bAutoDelete;
}

// Static members

static DWORD WINAPI ThreadProc(LPVOID pData)
{
T* pThis = static_cast(pData);

#if defined(_MT) || defined(_DLL)
ATLTRY( ::_endthreadex(pThis->Run()) );
if( pThis->m_bAutoDelete )
delete pThis;
return 0;
#else
DWORD dwRet = 0;
ATLTRY( dwRet = pThis->Run() );
if( pThis->m_bAutoDelete )
delete pThis;
return dwRet;
#endif // _MT
}

// Overridables

DWORD Run()
{
_ASSERTE(false); // must override this
//
// Sample thread loop...
//
// while( !IsAborted() ) {
// ...
// }
//
return 0;
}
};


//---------------------------------------------------------------
// CThreadImplEx

template<typename TStopPolicy>
class CThreadImplExT
: public CThread
, public TStopPolicy
{
typedef std::tr1::functionvoid)> ThreadFunc;

public:
bool m_bAutoDelete; // Thread class will delete itself upon thread exit?
bool m_bAutoCleanup; // Thread class will wait for thread completion upon scope exit?

ThreadFunc m_fThread; // Thread work function

public:
CThreadImplExT()
: m_bAutoDelete(false)
, m_bAutoCleanup(true)
{
}

~CThreadImplExT()
{
if( m_bAutoCleanup )
Stop();
}

// Register Thread work function
void RegisterFunc(ThreadFunc func)
{
m_fThread = func;
}

// Operations

bool Start()
{
if( !_ClearAbort() )
return FALSE;
if( !Create(ThreadProc, reinterpret_cast(this)) )
return FALSE;

return TRUE;
}

void Stop(DWORD dwTime = INFINITE)
{
if( !Abort() )
return;

if( WaitForThread(dwTime) )
Terminate(-1);

Release();
}

bool Abort()
{
if( m_hThread == NULL )
return FALSE;
if( !_Abort() )
return FALSE;
if( m_bSuspended )
Resume();

return TRUE;
}

bool IsAborted() const
{
_ASSERTE(m_hThread);

return _IsAborted();
}

void SetAutoClean(bool bAutoClean = true)
{
m_bAutoCleanup = bAutoClean;
}

void SetDeleteOnExit(bool bAutoDelete = true)
{
m_bAutoDelete = bAutoDelete;
m_bAutoCleanup = !bAutoDelete;
}

// Static members

static DWORD WINAPI ThreadProc(LPVOID pData)
{
CThreadImplExT* pThis = reinterpret_cast(pData);

// Not Register?
if( pThis->m_fThread == NULL )
return -1L;

#if defined(_MT) || defined(_DLL)
ATLTRY( _endthreadex(pThis->m_fThread()) );
if( pThis->m_bAutoDelete )
delete pThis;
return 0;
#else
DWORD dwRet = 0;
ATLTRY( dwRet = pThis->pThis->m_fThread() );
if( pThis->m_bAutoDelete )
delete pThis;
return dwRet;
#endif // _MT
}
};

typedef CThreadImplExT ThreadImplEx;
typedef CThreadImplExT ThreadImplExEvent;



//-----------------------------------------------------------
// CMessageThreadImpl

template< typename T >
class CMessageThreadImpl
: public CThreadImpl
{
public:
// Operations

bool PostQuitMessage()
{
_ASSERTE(m_hThread);
if( m_hThread == NULL )
return FALSE;

return ::PostThreadMessage(m_dwThreadID, WM_QUIT, 0, 0L);
}

bool PostMessage(UINT uMsg, WPARAM wParam = 0, LPARAM lParam = 0L)
{
_ASSERTE(m_hThread);
if( m_hThread == NULL )
return FALSE;

return ::PostThreadMessage(m_dwThreadID, uMsg, wParam, lParam);
}

// Overridables

void InitQueue()
{
}

void CloseQueue()
{
}

void ProcessWindowMessage(LPVOID /*pReserved*/, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& /*lResult*/, DWORD /*dwReserved*/)
{
_ASSERTE(false); // must override this
}

// Implementation

DWORD Run()
{
T* pT = static_cast(this);
MSG msg;
::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
pT->InitQueue();
while( !IsAborted() )
{
int iRet = (int)
::GetMessage(&msg, NULL, 0, 0);
if( iRet <= 0 )
break;

LRESULT lResult = 0;
pT->ProcessWindowMessage(NULL, msg.message, msg.wParam, msg.lParam, lResult, 0L);
}

pT->CloseQueue();
return 0;
}
};


//--------------------------------------------------------------
// CMessageThreadImplEx

template<typename StopPolicyT>
class CMessageThreadImplExT
: public CThreadImplExT
{
typedef std::tr1::function<void(MSG &, LRESULT &)> ThreadMessageFunc;

public:
ThreadMessageFunc m_fMessageFunc;

protected:
void RegisterFunc(ThreadFunc);

public:
// Operations

void RegisterMessageFunc(ThreadMessageFunc func)
{
m_fMessageFunc = func;
m_fThread = std::tr1::bind(&CMessageThreadImplExT::Run, this);
}

bool PostQuitMessage()
{
_ASSERTE(m_hThread);
if( m_hThread == NULL )
return FALSE;

return 0 != ::PostThreadMessage(m_dwThreadID, WM_QUIT, 0, 0L);
}

bool PostMessage(UINT uMsg, WPARAM wParam = 0, LPARAM lParam = 0L)
{
_ASSERTE(m_hThread);
if( m_hThread == NULL )
return FALSE;

return 0 != ::PostThreadMessage(m_dwThreadID, uMsg, wParam, lParam);
}

// Implementation

DWORD Run()
{
assert(m_fMessageFunc != NULL);
// Not Register?
if( m_fMessageFunc == NULL )
return -1L;

MSG msg;
::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);

while( !IsAborted() )
{
LRESULT lResult = 0;
m_fMessageFunc(msg, lResult);
if( lResult != S_OK )
break;
}


return 0;
}
};

typedef CMessageThreadImplExT MessageThreadImplEx;
typedef CMessageThreadImplExT MessageThreadImplExEvent;



}

#endif // __THREAD_THREAD_HPP


簡單介紹下各個類:

  • CThreadT很簡單,就是對thread的句柄包裝而已,一個簡單的wrapper。對他有個模板參數bool,是否需要在析構的時候釋放自己(熟悉WTL的朋友笑了~)。

  • CThreadStopAtBool和CThreadStopAtEvent是線程退出的策略,知道C++ Policy機制的朋友笑了~

  • CThreadImpl是線程的再次包裝,如果客戶端要使用此類來進行線程工作,需要繼承此類,並且提供DWORD Run()簽名函數,因爲使用了靜多態的手法(熟悉ATL的朋友笑了~),但是並不推薦使用此類,因爲它讓客戶端代碼和線程耦合起來了,悲劇~

  • CThreadImplExT是針對CThreadImpl會和客戶端類耦合的一個擴展類,它使客戶端使用線程非常方便,在上面的使用方式中展現了~

  • CMessageThreadImpl和CMessageThreadImplExT是對線程接受消息的一個擴展,原理類似CThreadImpl和CThreadImplExT~

 

當然,上述的線程組件代碼並不是人見人愛,希望能聽到各種意見~

再次,我提供了使用此組件的配套示例代碼,歡迎下載(右鍵下載)測試~(當然要把後綴gif替換爲rar,熟悉的人笑了~)

猛擊這裏 這裏~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章