基於MFC的編寫線程快速入門
程式員之家 作者:不詳 日期:2003-2-1 19:19:00
--------------------------------------------------------------------------------
對於新手,編寫線程,不知從何下手,不知編寫線程要做那些,下面給出一個線程的簡要架構
//////////////////////////////////////////////////////////////
//定義線程類YourThread.h
#if !defined(YOURTHREAD_INCLUDE_FILE)
#define YOURTHREAD_INCLUDE_FILE
class CYourThread :public CWinThread
{
....
DECLARE_DYNCREATE(CYourThread)
public:
CYourThread(); // protected constructor used by dynamic creation
// Attributes
public:
int m_bCloseFlag;
HANDLE m_hEventKill;
HANDLE m_hEventDead;
//操件
public:
void KillThread(); //清除本線程
protected:
virtual void SingleStep();
virtual void Delete();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CEgClientCacheThread)
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
virtual int Run();
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CYourThread();
// Generated message map functions
//{{AFX_MSG(CEgClientCacheThread)
// NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
}
#ednif
////////////////////////////////////////////
//實現檔案YourThread.cpp
#include "stdafx.h"
#include "YourThread.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNCREATE(CYourThread, CWinThread)
CYourThread::CYourThread()
{
m_bAutoDelete = FALSE; //註:該成員為CWinThread的成員,如為TRUE,在CWinThread::Delete()將刪除線程
//置為FALSE不允許自動刪除線程自已
m_hEventKill = CreateEvent(NULL, TRUE, FALSE, NULL);
m_hEventDead = CreateEvent(NULL, TRUE, FALSE, NULL);
}
CYourThread::~CYourThread()
{
CloseHandle(m_hEventKill);
CloseHandle(m_hEventDead);
}
BOOL cYourThread::InitInstance()
{
// TODO: perform and per-thread initialization here
// avoid entering standard message loop by returning FALSE
return TRUE; //使用者介面線程,必須返回TRUE
//如是 背景工作執行緒,代碼如下
/*
while (WaitForSingleObject(m_hEventKill, 0) == WAIT_TIMEOUT)
SingleStep();
// 避免進入標準訊息迴圈,必須返回FALSE
return FALSE;
*/
}
CYourThread:SingleStep()
{
//你的線程必一次執行的任務,每一次你的線程得到控制權,都會執行這個函數。
}
//如是使用者介面線程,必須重載下面的函數
int CYourThread:Run
{
//注:正面的代碼 除了加註中文解釋的外,其他的與CWinThread::Run()是完全一致的
// for tracking the idle time state
ASSERT_VALID(this);
// for tracking the idle time state
BOOL bIdle = TRUE;
LONG lIdleCount = 0;
// acquire and dispatch messages until a WM_QUIT message is received.
for (;;)
{
SingleStep(); //執行本線程的單步函數
if(m_bCloseFlag ==TRUE) //指示線程關閉
{
return ExitInstance();
}
// phase2: pump messages while available
//必須用下列方式進行訊息迴圈,因為CAsyncSocket用了標準的Windows訊息迴圈來處理資料發送和接收入
while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)) //必須先用PeekMessage進行訊息檢查
{
if(!(::GetMessage(&m_msgCur, NULL, NULL, NULL))) //取訊息
return ExitInstance();
if (!PreTranslateMessage(&m_msgCur))
{
::TranslateMessage(&m_msgCur);
::DispatchMessage(&m_msgCur);
}
if (IsIdleMessage(&m_msgCur))
{
bIdle = TRUE;
lIdleCount = 0;
}
}
}
return ExitInstance();
}
int CYourThread::ExitInstance()
{
//如是使用者介面線程,此處完成你的清除任務
VERIFY(SetEvent(m_hEventDead)); //這一句只有使用者介面線程需要
return CWinThread::ExitInstance();
}
void CYourThread::Delete()
{
// calling the base here won't do anything but it is a good habit?????????????
//在CWinThread::Delete()如m_hAutoDelete為TRUE,則會刪掉本進程
CWinThread::Delete();
// acknowledge receipt of kill notification
VERIFY(SetEvent(m_hEventDead));
}
void CYourThread::KillThread()
{
// Note: this function is called in the context of other threads,
// not the thread itself.
// reset the m_hEventKill which signals the thread to shutdown
VERIFY(SetEvent(m_hEventKill));
// allow thread to run at higher priority during kill process
SetThreadPriority(THREAD_PRIORITY_ABOVE_NORMAL);
WaitForSingleObject(m_hEventDead, INFINITE);
//下面兩行只有背景工作執行緒才能要
/*
WaitForSingleObject(m_hThread, INFINITE);
delete this;
*/
}
////////////////////////////////////////////////
//啟動線程
void startYourThread()
{
CEgYourThread *pThread;
if(!(pThread = (CYourThread*)AfxBeginThread(RUNTIME_CLASS(CYourThread),
THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED)))
{
AfxMessageBox(_T("建立線程失敗"));
return ;
}
VERIFY(pThread->SetThreadPriority(THREAD_PRIORITY_IDLE)); //設定優先權
pEgThread->ResumeThread(); //啟動線程
}
///////////////////////////////////////////////////////
//下面是解釋
注意:
1 線程分兩類: 背景工作執行緒 和 使用者介面線程
2 使用者介面線程可以進行有如鍵盤輸入的使用者互動,而背景工作執行緒則沒有。當然正在訊息處理機制上也有差異。
3 線上程初始化也不同. 如上面的例子
4 在重複使用的線程上,背景工作執行緒與使用者介面線程的清除也不一樣.
5 多線程時,必須解決資源衝突問題,剛開始學寫線程時,可以用臨界法來解決這個問題
在外部定義一個全域變數
CRITICAL_SECTION m_csYourThreadLock; //線程同步鎖
在調用時初始化:
InitializeCriticalSection(&m_csYourThreadLock)
在退出所有線程後
DeleteCriticalSection(&m_csYourThreadLock)
在SingleStep()函數中,對共用資源的處理,加上這一臨界鎖
void CYourThread::SingleStep()
{
EnterCriticalSection(&m_csYourThreadLock);
// 共用資源處理代碼
LeaveCriticalSection(&m_csYourThreadLock);
//其他代碼
}