MFC类。
CWinThread类是MFC用来封装线程的,包括UI线程和工作者线程。因此每个MFC程序至少使用一个CWinThread
派生类。被MFC程序员熟知的
CWinApp应用类就从这里派生。
说明
Windows以消息驱动方式工作,每个WIN32应用程序都至少包含一个
消息队列和一个消息泵。消息队列建立在操作系统提供内存保留区中,消息泵不断搜寻消息队列,将取得的消息分发给应用程序的各个部分进行处理,这个过程叫做
消息循环。基本消息循环如下:
//从队列中获取消息
{
//转换消息参数
TranslateMessage(&msg);
//分发消息
}
Windows以线程封装
消息循环,封装消息循环的线程叫做用户界面线程,即UI线程。该线程可以创建并撤销窗口。此外,还有一种线程叫做工作者线程,它是辅助UI线程工作的,它没有消息循环,不能处理系统事件和窗口消息,也不能关联主窗口。
主线程和辅线程虽然享有共同的
虚拟地址空间,但各自占用独立的
CPU时间片,参与系统资源的竞争。所以,可以使用辅线程完成经常性的、耗费机时的数据处理工作(例如网络通信),减轻UI线程的负担,确保UI线程及时响应用户的窗口操作。根据需要,一个应用程序中也可以创建多个UI线程。
成员函数
下面介绍几个实用的
CWinThread类成员函数。
虚函数InitInstance
Windows允许同时运行一个应用程序的多个备份,又称为运行一个程序的多个实例。
InitInstance就是“初始化实例”的意思,可见,它是在实例创建时首先被调用的。应用程序总要
重载这个
虚函数,进行系统设置,创建运行环境。例如,主窗口一定要在InitInstance()中创建,因为该函数退出后就进入该线程的
消息循环。
虚函数Run
该函数提供UI
线程的
消息循环,即反复地提取消息,分发消息,直到收到WM_QUIT退出循环,线程随即结束。在循环中,如果当前没有收到消息,则调用空闲消息处理程序OnIdle() 。以下是该函数的完整定义。
virtual int CWinThread::Run()
{
ASSERT_VALID(this);
//是否要做空闲处理
BOOL bIdle = TRUE;
//用户记录空闲处理已经连接执行的次数
LONG lIdleCount = 0;
//acquire and dispatch messages until a WM_QUIT message is received.
for (;;)
{
//如果空闲状态为真,且
消息队列为空,则进行空闲处理
while(bIdle && !::
PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
{
//PeekMessage()用于检查消息队列是否为空,但并不处理消息
//调用空闲处理程序,如果返回零,说明空闲处理已全部完成
if (!OnIdle(lIdleCount++))
bIdle = FALSE;
}
//空闲处理循环结束,进入消息泵循环
do
{
//调用消息泵,提取消息并分发消息
return ExitInstance();
//根据刚处理的消息类型,判断是否应该在没有消息到来时立即进行空闲处理
if (
IsIdleMessage(&m_msgCur))
{
bIdle = TRUE;
//在重新进行空闲处理前,清空空闲处理的执行次数
lIdleCount = 0;
}
} while (::
PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
}
ASSERT(FALSE); //不可能执行的语句
}
PumpMessage
//省略了调试信息的输出功能
BOOL CWinThread::
PumpMessage()
{
ASSERT_VALID(this);
//取出
消息队列中的第一个消息,直到取得消息,该函数才返回
if (!::
GetMessage(&m_msgCur, NULL, NULL, NULL))
{
//收到WM_QUIT消息
return FALSE;
}
//处理消息,但不处理WM_KICKIDLE
if (m_msgCur.message != WM_KICKIDLE && !
PreTranslateMessage(&m_msgCur))
{
//转换虚键消息到字符消息
//分发消息
}
return TRUE;
}
阅读
PumpMessage代码可知,消息泵并不处理WM_KICKIDLE消息,收到该消息后,直接返回。其实,WM_KICKIDLE消息被用来刺激空闲处理的执行,它作为一个空消息促使::
GetMessage()返回。
虚函数ExitInstance
与
InitInstance()相反,该函数是在退出
消息循环时执行,一般被框架调用,做最后的清理工作。但如果调用InitInstance()失败,
ExitInstance()也会被调用。可以
重载ExitInstance(),为线程做相关的清理工作。不要在除重载的Run()函数外的地方调用它。如果将CWinThread
成员变量m_bAutoDelete设为TRUE,CWinThread::ExitInstance()会删除当前的CWinThread对象。所以,如果在
堆栈中构造了UI线程对象,可以利用默认的ExitInstance()自动将它删除。