订阅
订阅
0有用+1
0

CWinThread

MFC中封装线程操作的类
CWinThread是微软基础类库(MFC)中封装线程操作的核心类,用于创建用户界面(UI)线程和工作者线程。所有MFC应用程序至少包含一个继承自该类的实例,如CWinApp主应用类即派生于此 [1]。UI线程通过消息循环处理窗口事件并管理窗口,而工作者线程用于执行后台任务,独立运行并与主线程共享内存。
该类通过虚函数管理线程生命周期:InitInstance负责初始化(如窗口创建),Run驱动消息循环及空闲处理,ExitInstance用于资源清理。消息泵机制通过PumpMessage实现消息分发,处理WM_QUIT时终止循环。成员变量m_bAutoDelete设置为TRUE时线程对象自动删除。开发者通常重载InitInstance和ExitInstance,Run方法多保持默认。MFC提供AfxBeginThread函数创建线程,支持优先级、堆栈大小等参数配置,并通过CCriticalSectionCEvent等同步类实现线程安全。
中文名
CWinThread
外文名
CWinThread
释    义
MFC用来封装的线程

说明

播报
编辑
Windows以消息驱动方式工作,每个WIN32应用程序都至少包含一个消息队列和一个消息泵。消息队列建立在操作系统提供内存保留区中,消息泵不断搜寻消息队列,将取得的消息分发给应用程序的各个部分进行处理,这个过程叫做消息循环。基本消息循环如兆归下:
//从队戒燥阿虹列中获取消息
while(GetMessage套付归(&msg,0,0,0))
{
//转付叠射换消息参数
TranslateMessage(&msg);
//分发消主祝息
枣祝祖凳辣墓}
Windows以线程封装消息循环,封装消息循环的线程叫做用户界面线程,即UI线程。该线程可以创建并撤销窗口。此外,还有一种线程叫做工作者线程,它是辅助UI线程工作的,它没有消息循环,不能处理系统事件和窗口消息,也不能关联主窗口。主线程和辅线程虽然享有共同的虚拟地址空间,但各自占用独立的CPU时间片,参与系统资源的竞争。所以,可以使用辅线程完成经常性的、耗费机时的数据处理润店工作(例如网络通信),减轻UI线程的负担,确保UI线程及时响应用户的窗口操作。根据需要,一个应用程序中也可以创建多个UI线程。

线程类型

播报
编辑
CWinThread支持两种泛型类型的线程:辅助线程和用户界面线程。辅助线程没有消息泵,通常用于处理后台任务,如后台计算。 [3] [9]创建辅助线程相对简单,通常无需从CWinThread派生新类,可直接使用CWinThread类。通过调用AfxBeginThread函数并传入控制函数的地址及相关参数即可创建并启动辅助线程。 [3] [9]
用户界面线程具有消息泵,可以处理来自系统的消息。MFC应用程序的主线程通常由CWinApp派生类实现,是用户界面线程的示例。其他用户界面线程也可以直接从CWinThread派生。创建用户界面线程时,需要向AfxBeginThread传递指向从CWinThread派生类的CRuntimeClass信息,并重写InitInstance成员函数以完成初始化。 [3] [10]两种线程的核心区别在于是否拥有消息泵,辅助线程专注于后台处理,用户界面线程处理用户界面函数。 [3-4] [9]

创建与启动

播报
编辑
在MFC中,CWinThread是所有线程的基类,封装了操作系统线程功能的一部分 [4]。创建线程的主要方法是调用全局函数AfxBeginThread。MFC支持两种类型的线程:辅助线程和用户界面线程。辅助线程没有消息泵,通常用于执行后台计算等无需消息处理的任务。用户界面线程具有一个消息泵和处理来自系统收到的消息,CWinApp即派生自CWinThread [1] [3-4]

使用AfxBeginThread创建线程

AfxBeginThread有两个重载版本,一个只能创建工作线程,另一个可以创建用户界面线程或工作线程 [5] [8-9]。对于工作线程,需要向AfxBeginThread传递控制函数的地址和要传递给控制函数的参数。控制函数应具有原型UINT MyControllingFunction( LPVOID pParam ),线程随该函数的开始而启动,结束而终止 [5] [9]。对于用户界面线程,需要向AfxBeginThread传递一个派生于CWinThread的类的CRuntimeClass信息。调用AfxBeginThread会创建并初始化CWinThread对象,启动线程,并返回指向该对象的指针 [2-3] [5] [9]。创建时可指定的可选参数包括优先级、堆栈大小、创建标志(如CREATE_SUSPENDED)和安全属性 [3] [9]

两阶段构造法

除了直接调用AfxBeginThread,还可以通过先构造一个CWinThread派生类的对象,再调用该对象的CreateThread成员函数来创建和启动线程。这种两阶段构造方法适用于需要在线程连续创建和停止过程中重用同一个CWinThread对象的场景 [3]

成员函数

播报
编辑
下面介绍几个实用的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
{
//调用消息泵,提取消息并分发消息
//如果收到WM_QUIT消息,则退出消息循环
if (!PumpMessage())
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))
{
//转换虚键消息到字符消息
::TranslateMessage(&m_msgCur);
//分发消息
::DispatchMessage(&m_msgCur);
}
return TRUE;
}
阅读PumpMessage代码可知,消息泵并不处理WM_KICKIDLE消息,收到该消息后,直接返回。其实,WM_KICKIDLE消息被用来刺激空闲处理的执行,它作为一个空消息促使::GetMessage()返回。
虽然Run()是虚拟函数,但很少被重载
虚函数ExitInstance
InitInstance()相反,该函数是在退出消息循环时执行,一般被框架调用,做最后的清理工作。但如果调用InitInstance()失败,ExitInstance()也会被调用。可以重载ExitInstance(),为线程做相关的清理工作。不要在除重载的Run()函数外的地方调用它。如果将CWinThread成员变量m_bAutoDelete设为TRUE,CWinThread::ExitInstance()会删除当前的CWinThread对象。所以,如果在堆栈中构造了UI线程对象,可以利用默认的ExitInstance()自动将它删除。

核心技术

播报
编辑
CWinThread是微软基础类库(MFC)中封装操作系统线程功能的核心基类,用于创建用户界面线程和工作者线程。 [1] [4]用户界面线程具有消息泵并处理系统消息,例如从CWinApp派生的主线程;辅助线程则没有消息泵。其核心机制包括由虚函数管理的线程生命周期以及消息泵和空闲处理循环。 [3] [6]
CWinThread::InitInstance是一个必须由用户界面线程重写的虚函数,用于执行线程首次创建时必须完成的任务,成功初始化返回非零值。 [10-11]CWinThread::Run是包含线程消息泵的控制函数,驱动默认的消息循环和空闲处理。 [3] [6]CWinThread::ExitInstance可重写以在线程终止时进行清理。 [3]
消息泵机制由Run函数通过PumpMessage函数实现消息的获取、转换和分发。 [3] [6]当线程消息队列为空时,Run函数会循环调用OnIdle成员函数以执行后台任务。 [6-7]CWinThread::OnIdle可重写此虚函数以执行线程特定的空闲时间处理,其lCount参数可用来判断空闲时长,函数应返回0表示不需要更多空闲时间。 [7]