分享一個事務處理執行緒類
Windows下建立執行緒是很簡單的,具體建立執行緒的程式碼可以用AfxBeginThread(),也可以用CreateThread(),也可以用_beginthreadex()。大家寫的恐怕手都磨出老繭了。
但是,有時候我們經常會遇到一種情況,比如說每隔一會我就要做一些事情,而且必須線上程裡做。這時候該怎麼辦呢?最簡單的辦法當然是,每次都建立一個執行緒就OK了。但是身為程式設計師,我們不能對自己的要求僅僅是程式能執行就行了。作為一種更節約資源的辦法,在程式啟動的時候建立執行緒,後面在需要做一些事情的時候,把這些事情作為事務提交給執行緒處理。
當然了,以現在計算機的執行能力來說,每次都建立一個執行緒也不是什麼問題。對於普通使用者來說,程式每秒建立10個執行緒和程式一共只建立一個執行緒,基本上根本就感覺不出差別。但是我們自己必須知道,建立一個執行緒這樣的核心物件,其實開銷還是比較大的。從另一方面來說,一共只建立一個執行緒,方便對執行緒進行狀態檢測、控制。如果程式是執行在伺服器端的話,那就更應該這樣做了,每次都建立一個執行緒絕對不是個好主意。
這裡,我提供一個基本的事務處理執行緒類的模板。
Transaction.h
#ifndef _WINDOWS_THREAD_TRANSACTION_H_ #define _WINDOWS_THREAD_TRANSACTION_H_ #pragma once class CRunnable { public: virtual void Run(void)=0; }; class CTransaction { public: CTransaction(void); ~CTransaction(void); void Init(); void Clear(); void Do(CRunnable & run); protected: void* m_hThread; unsigned m_ThreadID; static unsigned __stdcall ThreadFunc(void* pArguments); }; #endif
Transaction.cpp
#include "Transaction.h" #include <windows.h> #include <process.h> #define UM_THREAD_NOTIFY (WM_USER + 150) CTransaction::CTransaction(void):m_hThread(NULL),m_ThreadID(0) { } CTransaction::~CTransaction(void) { if (0 != m_ThreadID) { Clear(); } if (NULL != m_hThread) { ::CloseHandle(m_hThread); } } void CTransaction::Init() { m_hThread = (void*)_beginthreadex( NULL, 0, &CTransaction::ThreadFunc, this, 0, &m_ThreadID); } void CTransaction::Clear() { ::PostThreadMessage((DWORD)m_ThreadID, WM_QUIT,0,0); ::Sleep(50); DWORD dwExitCode = 0; ::GetExitCodeThread(m_hThread, &dwExitCode); if (STILL_ACTIVE == dwExitCode) { DWORD dw = ::WaitForSingleObject(m_hThread ,1000); switch (dw) { case WAIT_TIMEOUT: ::TerminateThread(m_hThread, 1); break; default: ; } } m_ThreadID = 0; // 執行緒ID置0做為退出標誌 } unsigned __stdcall CTransaction::ThreadFunc(void* pArguments) {; CTransaction *p = (CTransaction*)pArguments; MSG msg; ZeroMemory(&msg,sizeof(MSG)); ::PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); CRunnable * pRun = NULL; BOOL bRet; while ((bRet = ::GetMessage( &msg, 0, WM_QUIT, UM_THREAD_NOTIFY)) != 0) { if (bRet == -1) { // handle the error and possibly exit continue; } if (UM_THREAD_NOTIFY == msg.message) { pRun = (CRunnable*)msg.wParam; pRun->Run(); } } _endthreadex(0); return 0; } void CTransaction::Do(CRunnable & run) { ::PostThreadMessage((DWORD)m_ThreadID, UM_THREAD_NOTIFY, (WPARAM)&run, 0); }
這裡提供了一個執行緒事務處理的基本的模型。
具體的使用說明。對於要處理的事務,繼承自CRunnable類,實現它的Run()方法。宣告一個處理執行緒的全域性或模組物件,比如命名為m_tran。在程式或者程式介面的初始化函式中呼叫m_tran.Init();對於事務類,宣告相應的事務物件,必須是模組級物件或全域性物件,不能是區域性物件。比如說命名為m_myTran。
在要執行的時候呼叫
m_tran.Do(m_myTran);
這樣就可以了。這個模型的實現利用了windows的執行緒訊息。因為只建立了一個執行緒,所以基本不需要考慮互斥之類的問題。當然如果另外還建立了其他的執行緒,處理的事務中有操作其他執行緒也有操作的資料,那就需要考慮了。
這個模型應付一般的應用場景是沒問題的。但如果事務處理的數量非常大,連續請求,就不太合適了。因為windows執行緒訊息的響應速度並不很快。這時候相對來說效率就不很高。這種情況下就不適合用windows執行緒訊息來控制,而可以用執行緒間隔一定時間來檢查是否有事務需要處理,處理完事務後立即連續檢查,沒有新的事務則待會再檢查的方式來控制了。