应该先产生 个 CWinThread 对象,再呼叫其成员函式CreateThread 或全域函式AfxBeginThread 将执行 绪产生出来

虽然MFC 程序只会有 个CWinApp 对象,而CWinApp 衍生自CWinThread,但并不
是说 个MFC 程序只能有 个CWinThread 对象。每当你需要 个额外的执行绪,不
应该在MFC 程序 直接呼叫::CreateThread 或_beginthreadex,应该先产生 个
CWinThread 对象,再呼叫其成员函式CreateThread 或全域函式AfxBeginThread 将执行
绪产生出来。当然, 现在你必然已经可以推测到,CWinThread::CreateThread 或
AfxBeginThread 内部呼叫了::CreateThread 或_beginthreadex ( 事实 答案是
_beginthreadex)。
这看起来颇有值得商议之处:为什么CWinThread 建构式不帮我们呼叫AfxBeginThread
呢?似乎CWinThread 为德不卒。
图14-5 就是CWinThread 的相关原始码。
第14 章MFC 多绪程序设计
757
#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 CommonConstruct();
#0008 }
#0009
#0010 CWinThread::CWinThread()
#0011 {
#0012 m_pThreadParams = NULL;
#0013 m_pfnThreadProc = NULL;
#0014
#0015 CommonConstruct();
#0016 }
#0017
#0018 void CWinThread::CommonConstruct()
#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 {
第 篇深入MFC 程序设计
758
#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);
第14 章MFC 多绪程序设计
759
#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:
第 篇深入MFC 程序设计
760
CWinThread* pThread = AfxBeginThread(ThreadFunc, &Param);
...
UINT ThreadFunc (LPVOID pParam)
{
...
}
AfxBeginThread 事实 共可以接受六个参数,分别是:
CWinThread* AFXAPI AfxBeginThread(AFX_THREADPROC pfnThreadProc,
LPVOID pParam,
int nPriority = THREAD_PRIORITY_NORMAL,
UINT nStackSize = 0,
DWORD dwCreateFlags = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);
参数 pfnThreadProc 表示执行绪函式。参数 pParam 表示要传给执行绪函式的参
数。参数 nPriority 表示优先权的微调值,预设为THREAD_PRIORITY_NORMAL,也
就是没有微调。参数 nStackSize 表示堆栈的大小,默认值0 则表示堆栈最大容量为
1MB。参数五dwCreateFlags 如果为默认值0,就表示执行绪产生后立刻开始执行;如
果其值为CREATE_SUSPENDED,就表示执行绪产生后先暂停执行。之后你可以使用
CWinThread::ResumeThread 重新执行它。参数六lpSecurityAttrs 代表新执行绪的安全防
护属性。默认值NULL 表示此 属性与其产生者(也是个执行绪)的属性相同。
在这里我们遭遇到 个困扰。执行绪函式是由系统呼叫的,也就是个callback 函式,不
容许有this 指标参数。所以任何 般的C++ 类别成员函式都不能够拿来当做执行绪函
式。它必须是个全域函式,或是个C++ 类别的static 成员函式。其原因我已经在第6
章的「Callback 函式」 节 描述过了,而采用全域函式或是C++ static 成员函式,其
间的优劣因素我也已经在该节讨论过。
执行绪函式的型态AFX_THREADPROC 定义于AFXWIN.H 之 :
// in AFXWIN.H
typedef UINT (AFX_CDECL *AFX_THREADPROC)(LPVOID);
所以你应该把本身的执行绪函式宣告如 (其 的pParam 是个指标,在实用 可以指
向程序员自定的数据结构):
UINT ThreadFunc (LPVOID pParam);
第14 章MFC 多绪程序设计
761
否则,编译时会获得这样的错误讯息:
error C2665: 'AfxBeginThread' : none of the 2 overloads can convert
parameter 1 from type 'void (unsigned long *)'
有时候我们会让不同的执行绪使用相同的执行绪函式,这时候你就得特别注意到执行绪
函式使用全域变量或静态变量时,数据共享所引发的严重性(有好有坏)。至于放置在
堆栈 的变量或对象,都不会有问题,因为每 个执行绪自有 个堆栈。
产生一个UI Thread
UI thread 可不能够光由 个执行绪函式来代表,因为它要处理讯息,它需要 个讯息回
路。好得很,CWinThread::Run 里头就有 个讯息回路。所以,我们应该先从CWinThread
衍生 个自己的类别,再呼叫AfxBeginThread 产生 个CWinThread 对象:
class CMyThread : public CWinThread
{
DECLARE_DYNCREATE(CMyThread)
public:
void BOOL InitInstance();
};
IMPLEMENT_DYNCREATE(CMyThread, CWinThread)
BOOL CMyThread::InitInstance()
{
...
}
CWinThread *pThread = AfxBeginThread(RUNTIME_CLASS(CMyThread));
我想你对RUNTIME_CLASS 宏已经不陌生了,第3章和第8章都有这个宏的原始码
展现以及意义解释。AfxBeginThread 是 小节同名函式的 个overloaded 函式, 共
可以接受五个参数,分别是:
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值