深入浅出MFC第2版(PDF格式)-第151部分
按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
MltiThrd 。这一节,我要介绍MFC 多线程程序的写法。
探索CWinThread
就像CWinApp 对象代表一个程序本身一样,CWinThread 对象代表一个执行线程本身。这
个MFC 类别我们曾经看过,第6章讲「MFC 程序的生死因果」时,讲到「CWinApp::Run
程序生命的活水源头」,曾经追踪过CWinApp::Run 的源头CWinThread::Run (里面有
一个消息循环)。可见程序的「执行事实」系发生在CWinThread 对象身上,而CWinThread
对象必须要(必然会)产生一个执行线程。
我希望「CWinThread 对象必须要(必然会)产生一个执行线程」这句话不会引起你的误会,
以为程序在application object (CWinApp 对象)的构造式必然有个动作最终调用到
CreateThread 或_beginthreadex 。不,不是这样。想想看,当你的Win32 程序执行起来,
你的程序并没有调用CreateProcess 为自己做出代表自己的那个进程,也没有调用
CreateThread 为自己做出代表自己的主执行线程(primary thread )的那个执行线程。为你的
程序产生第一个进程和执行线程,是系统加载器以及核心模块(KERNEL32 )合作的结果。
所以,再次循着第6章一步步剖析的步骤,MFC 程序的第一个动作是CWinApp::CWinApp
(比WinMain 还早),在那里没有「产生执行线程」的动作,而是已经开始在收集执行线程
755
…………………………………………………………Page 818……………………………………………………………
第篇 深入 MFC 程式設計
的相关信息了:
// in MFC 4。2 APPCORE。CPP
CWinApp::CWinApp(LPCTSTR lpszAppName)
{
。。。
// initialize CWinThread state
AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
AFX_MODULE_THREAD_STATE* pThreadState = pModuleState…》m_thread;
ASSERT(AfxGetThread() == NULL);
pThreadState…》m_pCurrentWinThread = this;
ASSERT(AfxGetThread() == this);
m_hThread = ::GetCurrentThread();
m_nThreadID = ::GetCurrentThreadId();
。。。
}
虽然MFC 程序只会有一个CWinApp 对象,而CWinApp 衍生自CWinThread,但并不
是说一个MFC 程序只能有一个CWinThread 对象。每当你需要一个额外的执行线程,不
应该在MFC 程序中直接调用::CreateThread 或_beginthreadex,应该先产生一个
CWinThread 对象,再调用其成员函数CreateThread 或全域函数AfxBeginThread 将执行
线程产生出来。当然, 现在你必然已经可以推测到,CWinThread::CreateThread 或
AfxBeginThread 内部调用了::CreateThread 或_beginthreadex (事实上答案是
_beginthreadex )。
这看起来颇有值得商议之处:为什么CWinThread 构造式不帮我们调用AfxBeginThread
呢?似乎CWinThread 为德不卒。
图14…5 就是CWinThread 的相关源代码。
756
…………………………………………………………Page 819……………………………………………………………
14 MFC
第 章 多緒程式設計
#0001 // in MFC 4。2 THRDCORE。CPP
#0002 CWinThread::CWinThread(AFX_THREADPROC pfnThreadProc; LPVOID pParam)
#0003 {
#0004 m_pfnThreadProc = pfnThreadProc;
#0005 m_pThreadParams = pParam;
#0006
#0007 monConstruct();
#0008 }
#0009
#0010 CWinThread::CWinThread()
#0011 {
#0012 m_pThreadParams = NULL;
#0013 m_pfnThreadProc = NULL;
#0014
#0015 monConstruct();
#0016 }
#0017
#0018 void CWinThread::monConstruct()
#0019 {
#0020 m_pMainWnd = NULL;
#0021 m_pActiveWnd = NULL;
#0022
#0023 // no HTHREAD until it is created
#0024 m_hThread = NULL;
#0025 m_nThreadID = 0;
#0026
#0027 // initialize message pump
#0028 #ifdef _DEBUG
#0029 m_nDisablePumpCount = 0;
#0030 #endif
#0031 m_msgCur。message = WM_NULL;
#0032 m_nMsgLast = WM_NULL;
#0033 ::GetCursorPos(&m_ptCursorLast);
#0034
#0035 // most threads are deleted when not needed
#0036 m_bAutoDelete = TRUE;
#0037
#0038 // initialize OLE state
#0039 m_pMessageFilter = NULL;
#0040 m_lpfnOleTermOrFreeLib = NULL;
#0041 }
#0042
#0043 CWinThread* AFXAPI AfxBeginThread (AFX_THREADPROC pfnThreadProc; LPVOID pParam;
#0044 int nPriority; UINT nStackSize; DWORD dwCreateFlags;
#0045 LPSECURITY_ATTRIBUTES lpSecurityAttrs)
#0046 {
757
…………………………………………………………Page 820……………………………………………………………
第篇 深入 MFC 程式設計
#0047 CWinThread* pThread = DEBUG_NEW CWinThread (pfnThreadProc; pParam);
#0048
#0049 if (!pThread…》CreateThread (dwCreateFlags|CREATE_SUSPENDED; nStackSize;
#0050 lpSecurityAttrs))
#0051 {
#0052 pThread…》Delete();
#0053 return NULL;
#0054 }
#0055 VERIFY(pThread…》SetThreadPriority(nPriority));
#0056 if (!(dwCreateFlags & CREATE_SUSPENDED))
#0057 VERIFY(pThread…》ResumeThread() != (DWORD)…1);
#0058
#0059 return pThread;
#0060 }
#0061
#0062 CWinThread* AFXAPI AfxBeginThread (CRuntimeClass* pThreadClass;
#0063 int nPriority; UINT nStackSize; DWORD dwCreateFlags;
#0064 LPSECURITY_ATTRIBUTES lpSecurityAttrs)
#0065 {
#0066 ASSERT(pThreadClass != NULL);
#0067 ASSERT(pThreadClass…》IsDerivedFrom(RUNTIME_CLASS(CWinThread)));
#0068
#0069 CWinThread* pThread = (CWinThread*)pThreadClass…》CreateObject();
#0070
#0071 pThread…》m_pThreadParams = NULL;
#0072 if (!pThread…》CreateThread (dwCreateFlags|CREATE_SUSPENDED; nStackSize;
#0073 lpSecurityAttrs))
#0074 {
#0075 pThread…》Delete();
#0076 return NULL;
#0077 }
#0078 VERIFY(pThread…》SetThreadPriority(nPriority));
#0079 if (!(dwCreateFlags & CREATE_SUSPENDED))
#0080 VERIFY(pThread…》ResumeThread() != (DWORD)…1);
#0081
#0082 return pThread;
#0083 }
#0084
#0085 BOOL CWinThread::CreateThread (DWORD dwCreateFlags; UINT nStackSize;
#0086 LPSECURITY_ATTRIBUTES lpSecurityAttrs)
#0087 {
#0088 // setup startup structure for thread initialization
#0089 _AFX_THREAD_STARTUP startup; memset(&startup; 0; sizeof(startup));
#0090 startup。pThreadState = AfxGetThreadState();
#0091 startup。pThread = this;
#0092 startup。hEvent = ::CreateEvent(NULL; TRUE; FALSE; NULL);
758
…………………………………………………………Page 821……………………………………………………………
14 MFC
第 章 多緒程式設計
#0093 startup。hEvent2 = ::CreateEvent(NULL; TRUE; FALSE; NULL);
#0094 startup。dwCreateFlags = dwCreateFlags;
#0095 。。。
#0096 // create the thread (it may or may not start to run)
#0097 m_hThread = (HANDLE)_beginthreadex (lpSecurityAttrs; nStackSize;
#0098 &_AfxThreadEntry; &startup; dwCreateFlags | CREATE_SUSPENDED; (UINT*)&m_nThreadID);
#0099 。。。
#0100 }
图14…5 CWinThread 的相关源代码
产生执行线程, 为什么不直接用::CreateThread 或_beginthreadex ? 为什么要透过
CWinThread 对象? 我想你可以轻易从MFC 源代码中看出, 因为
CWinThread::CreateThread 和AfxBeginThread 不只是::CreateThread 的一层包装,更做
了一些application framework 所需的内部数据初始化工作,并确保使用正确的C runtime
library 版本。源代码中有:
#ifndef _MT
。。。 // 做些设定工作,不产生执行线程,回返。
#else
。。。 // 真正产生执行线程,回返。
#endif //!_MT)
的动作,只是被我删去未列出而已。
接下来我要把worker thread 和UI thread 的产生步骤做个整理。它们都需要调用
AfxBeginThread 以产生一个CWinThread 对象,但如果要产生一个UI thread ,你还必须
先定义一个CWinThread 衍生类别。
产生一个Worker Thread
Worker thread 不牵扯使用者接口。你应该为它准备一个执行线程函数, 然后调用
AfxBeginThread :
759
…………………………………………………………Page 822……………………………………………………………
第篇 深入 MFC 程式設計
CWinThread AfxBeginThread ThreadFunc
* pThread = ( ; &Param);