MFC多线程的创建
1.MFC多线程简介
MFC对多线程进行了一层简单的封装,在Visual C++中每个线程都是从CWinThread类继承而来的。每一个应用程序的执行都有一个主线程,这个主线程也是从CWinThread类继承而来的。可以利用CWinThread对象创建应用程序执行的其它线程。
MFC用CWinThread对象来表示所有线程。利用MFC可以创建两种线程,分别称之为工作者线程和用户界面线程。二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环。工作者线程没有消息机制,通常用来执行后台计算和维护任务,如冗长的计算过程,打印机的后台打印等。用户界面线程一般用于处理独立于其他线程执行之外的用户输入,响应用户及系统所产生的事件和消息等。但对于Win32的API编程而言,这两种线程是没有区别的,它们都只需线程的启动地址即可启动线程来执行任务。
2.MFC多线程基础
为了深入了解MFC下创建线程的方法,我们先深入学习一下CWinThread类。CWinThread类在MFC类结构中的位置如下图所示:
图1:CWinThread类在mfc类结构中的位置
详细的MFC类结构图请参考MSDN: http://msdn.microsoft.com/zh-cn/library/ws8s10w4(VS.90).aspx
首先看一下类CWinThread的声明。类CWinThread的声明在afxwin.h中:
/
Class CWinThread :publicCCmdTarget
{
DECLARE_DYNAMIC(CWinThread)
public:
//构造函数
CWinThread();
//用来具体创建线程的函数
BOOL CreateThread(DWORDdwCreateFlags = 0,UINTnStackSize = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs= NULL);
// Attributes
//主窗口,(通常使用AfxGetApp()->m_pMainWnd可以得到)
CWnd* m_pMainWnd; // main window(usually same AfxGetApp()->m_pMainWnd)
//活动窗口,可能不是主窗口
CWnd* m_pActiveWnd; // active mainwindow (may not be m_pMainWnd)
BOOL m_bAutoDelete; // enables'delete this' after thread termination
// only valid while running
//该线程的句柄
HANDLE m_hThread; // thisthread's HANDLE
operator HANDLE() const;
//该线程的ID
DWORD m_nThreadID; // thisthread's ID
//线程优先级
int GetThreadPriority();
BOOL SetThreadPriority(int nPriority);
// Operations
//挂起线程
DWORD SuspendThread();
//启动线程
DWORD ResumeThread();
//发送线程消息
BOOL PostThreadMessage(UINT message, WPARAM wParam, LPARAM lParam);
// Overridables
// 线程初始化,每个应用程序都可以重载该函数
virtual BOOL InitInstance();
// running and idle processing
virtual int Run();
virtual BOOL PreTranslateMessage(MSG*pMsg);
virtual BOOL PumpMessage(); // low level message pump
virtual BOOL OnIdle(LONGlCount);// return TRUEif more idle processing
virtual BOOL IsIdleMessage(MSG*pMsg); // checks for special messages
// thread termination
virtual int ExitInstance(); //default will 'delete this'
// Advanced: exception handling
virtual LRESULT ProcessWndProcException(CException*e,constMSG*pMsg);
// Advanced: handling messages sent to message filter hook
virtual BOOL ProcessMessageFilter(intcode,LPMSGlpMsg);
// Advanced: virtual access to m_pMainWnd
virtual CWnd* GetMainWnd();
// Implementation
public:
virtual ~CWinThread();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext&dc)const;
#endif
void CommonConstruct();
virtual void Delete();
// 'delete this' only if m_bAutoDelete == TRUE
public:
// constructor used by implementation of AfxBeginThread
CWinThread(AFX_THREADPROCpfnThreadProc,LPVOIDpParam);
// valid after construction
LPVOID m_pThreadParams;// generic parameters passed to starting function
AFX_THREADPROC m_pfnThreadProc;
// set after OLE is initialized
void (AFXAPI*m_lpfnOleTermOrFreeLib)(BOOL,BOOL);
COleMessageFilter* m_pMessageFilter;
protected:
BOOL DispatchThreadMessageEx(MSG* msg); // helper
void DispatchThreadMessage(MSG* msg); // obsolete
};
/
有些函数是不是很眼熟呀,在前面的文章中已经介绍和使用过啦。MFC类就是这样的,它无非就是简单封装一些API函数,并添加一些自己的函数而构成的。不用MFC我们照样可以编写很优秀的程序,MFC的宗旨就是简化程序设计,让你可以很容易入门和简单的使用,也催生了大量的程序员。但对喜欢刨根问底的朋友却是一道很厚的墙。
下面几个函数是多线程编程中经常用到的几个全局函数:
//创建工作线程
CWinThread* AFXAPIAfxBeginThread(
AFX_THREADPROC pfnThreadProc,//线程函数
LPVOID pParam,//传给线程函数的参数
int nPriority =THREAD_PRIORITY_NORMAL,//线程的优先级
UINT nStackSize = 0,//堆栈大小
DWORD dwCreateFlags = 0,//创建起始状态标志
LPSECURITY_ATTRIBUTES lpSecurityAttrs= NULL//线程的安全属性
);
//创建用户界面线程
CWinThread* AFXAPIAfxBeginThread(
CRuntimeClass* pThreadClass,//从CWinThread派生的类的RUNTIME_CLASS
int nPriority =THREAD_PRIORITY_NORMAL,//线程的优先级
UINT nStackSize = 0,// 堆栈大小
DWORD dwCreateFlags = 0,// 创建起始状态标志
LPSECURITY_ATTRIBUTESlpSecurityAttrs =NULL//线程的安全属性
);
//获取线程对象
CWinThread* AFXAPIAfxGetThread();
//获取当前消息
MSG* AFXAPIAfxGetCurrentMessage();
//结束线程执行
void AFXAPIAfxEndThread(UINTnExitCode,BOOLbDelete =TRUE);
//初始化线程
void AFXAPIAfxInitThread();
//终止线程执行
void AFXAPIAfxTermThread(HINSTANCEhInstTerm =NULL);
仔细阅读以上类的说明能学到不少东西:
(1) CWinThead类通过CreateThread()成员函数来创建线程,这个函数的声明和Win32APICreateThread()的参数相似
(2)每个函数在运行后都有一个句柄和ID号。
(3)通过设置属性m_bAutoDelete,可决定线程在运行结束后线程对象是否自动删除,它的访问权限是public型的,可以直接进行设置。一般情况下,线程对象的生命周期和线程的生命周期一致。如果你想改变线程对象的生命周期,可设置该属性为FALSE。
(4)MFC下的多线程仍然支持线程的挂起和启动。
(5)具有PreTranslateMessage()、PumpMessage()等函数,供用户界面线程的消息机制使用。
在MFC中实际上是调用AfxBeginThread()函数来创建线程的。那么为什么不直接使用::CreateThread()或_beginthread()函数来创建线程呢?只要看一下CWinThread类的实现中的相关代码就明白了。在thrdcore.cpp文件中的相关代码如下:
==========================================================================================================
CWinThread* AFXAPI AfxGetThread()
{
// check for current thread in module thread state
AFX_MODULE_THREAD_STATE* pState= AfxGetModuleThreadState();
CWinThread* pThread= pState->m_pCurrentWinThread;
return pThread;
}
MSG* AFXAPI AfxGetCurrentMessage()
{
_AFX_THREAD_STATE* pState= AfxGetThreadState();
ASSERT(pState);
return &(pState->m_msgCur);
}
CWinThread* AFXAPI AfxBeginThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam,int nPriority,UINT nStackSize, DWORD dwCreateFlags,
LPSECURITY_ATTRIBUTESlpSecurityAttrs)
{
#ifndef _MT
pfnThreadProc;
pParam;
nPriority;
nStackSize;
dwCreateFlags;
lpSecurityAttrs;
return NULL;
#else
ASSERT(pfnThreadProc!=NULL);
CWinThread* pThread=DEBUG_NEWCWinThread(pfnThreadProc,pParam);
ASSERT_VALID(pThread);
if (!pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED,nStackSize,
lpSecurityAttrs))
{
pThread->Delete();
return NULL;
}
VERIFY(pThread->SetThreadPriority(nPriority));
if (!(dwCreateFlags&CREATE_SUSPENDED))
VERIFY(pThread->ResumeThread() != (DWORD)-1);
return pThread;
#endif //!_MT)
}
CWinThread* AFXAPI AfxBeginThread(CRuntimeClass*pThreadClass,
int nPriority, UINT nStackSize,DWORD dwCreateFlags,