MFC架构之CWinThread类
2010年11月14日
我们知道,Windows以事件驱动方式工作,每个WIN32应用程序都至少包含一个消息队列和一个消息泵。消息队列建立在操作系统提供的内存保留区中,消息泵不断搜寻消息队列,将取得的消息分发给应用程序的各个部分进行处理,这个过程叫做消息循环。基本消息循环如下:
while(GetMessage(&msg,0,0,0)) { //转换消息参数 TranslateMesssage(&msg); //分发消息 DispatchMessage(&msg); } Windows以线程封装消息循环,封装消息循环的线程叫做用户界面线程,即UI线程。该线程可以创建并撤销窗口。此外还有一种线程叫做工作者线程,它是辅助UI线程工作的,它没有消息循环,不能处理系统事件和窗口消息,也不能关联主窗口。主线程和辅线程虽然享有共同的虚拟地址空间,但各自占用独立的CPU时间片,参与系统资源的竞争。所以,可以使用辅线程完成经常性的、耗费机时的数据处理工作(例如网络通信),减轻UI线程的负担,确保UI线程及时响应用户的窗口操作。根据需要,一个应用程序中也可以创建多个UI线程。
CWinThread类是MFC用来封装线程的,包括UI线程和工作者线程。因此每个MFC程序至少使用一个CWinThread派生类。被MFC程序员熟知的CWinApp应用类就从这里派生。
下面介绍几个实用的CWinThread类成员函数。
1.虚函数InitInstance
Windows允许同时运行一个应用程序的多个备份,又称为运行一个程序的多个实例。 InitInstance就是"初始化实例"的意思,可见,它是在实例创建时首先被调用的。应用程序总要重载这个虚函数,进行系统设置,创建运行环境。例如,主窗口一定要在InitInstance()中创建,因为该函数退出后就进入该线程的消息循环。
2.虚函数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()是虚拟函数,但很少被重载。
3.虚函数ExitInstance
与InitInstance()相反,该函数是在退出消息循环时执行,一般被框架调用,做最后的清理工作。但如果调用InitInstance()失败,ExitInstance()也会被调用。可以重载ExitInstance(),为线程做相关的清理工作。不要在除重载的Run()函数外的地方调用它。如果将CWinThread成员变量m_bAutoDelete设为 TRUE,CWinThread::ExitInstance()会删除当前的CWinThread对象。所以,如果在堆栈中构造了UI线程对象,可以利用默认的ExitInstance()自动将它删除。
4.虚函数virtual BOOL PreTranslateMessage(MSG *pMsg );
在消息在TranslateMessage和DispatchMessage之前过滤消息。
5.虚函数virtual BOOL OnIdle(LONG lCount);
在空闲时处理。
CWinThread的使用
常见的启动线程函数有三个:
CreateThread(), _beginThread(以及_beginThreadEx()),AfxBeginThread()
1和2是sdk函数,3是mfc函数
至于启动的是工作者线程还是UI线程,是由函数3的参数来决定的 ;
一个例子: class CUIThread : public CWinThread { DECLARE_DYNCREATE(CUIThread) protected: CUIThread(); // protected constructor used by dynamic creation // Attributes public: // Operations public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CUIThread) public: virtual BOOL InitInstance(); virtual int ExitInstance(); //}}AFX_VIRTUAL // Implementation protected: virtual ~CUIThread(); // Generated message map functions //{{AFX_MSG(CUIThread) // NOTE - the ClassWizard will add and remove member functions here. //}}AFX_MSG DECLARE_MESSAGE_MAP() }; //重载函数InitInstance()和ExitInstance() BOOL CUIThread::InitInstance() { CFrameWnd* wnd=new CFrameWnd; wnd->Create(NULL,"UI Thread Window"); wnd->ShowWindow(SW_SHOW); wnd->UpdateWindow(); m_pMainWnd=wnd; return TRUE; } //创建新的用户界面线程 void CUIThreadDlg::OnButton1() { CUIThread* pThread=new CUIThread(); pThread->CreateThread(); } 请注意以下两点:
1.在UIThreadDlg.cpp的开头加入语句: #include "UIThread.h"
2.把UIThread.h中类CUIThread()的构造函数的特性由 protected 改为 public。
用户界面线程的执行次序与应用程序主线程相同,首先调用用户界面线程类的InitInstance()函数,如果返回TRUE,继续调用线程的 Run()函数,该函数的作用是运行一个标准的消息循环,并且当收到WM_QUIT消息后中断,在消息循环过程中,Run()函数检测到线程空闲时(没有消息),也将调用OnIdle()函数,最后Run()函数返回,MFC调用ExitInstance()函数清理资源。
你可以创建一个没有界面而有消息循环的线程,例如:你可以从CWinThread派生一个新类,在InitInstance函数中完成某项任务并返回FALSE,这表示仅执行InitInstance函数中的任务而不执行消息循环,你可以通过这种方法,完成一个工作者线程的功能。
另一个例子: //.h 文件 #define WM_TEST WM_USER + 1 class CTestThread : public CWinThread { DECLARE_DYNCREATE(CTestThread) protected: CTestThread (); virtual ~CTestThread (); public: virtual BOOL InitInstance(); virtual int ExitInstance(); protected: afx_msg void OnTest(WPARAM wParam,LPARAM lParam); DECLARE_MESSAGE_MAP() }; //.Cpp 文件 #include "stdafx.h" #include "TestThread.h" IMPLEMENT_DYNCREATE(CTestThread, CWinThread) CTestThread::CTestThread() { } CTestThread::~CTestThread() { } BEGIN_MESSAGE_MAP(CTestThread, CWinThread) ON_THREAD_MESSAGE(WM_TEST,OnTest) END_MESSAGE_MAP() BOOL CTestThread::InitInstance() { return TRUE; } int CTestThread::ExitInstance() { return CWinThread::ExitInstance(); } void CTestThread::OnTest(WPARAM wParam,LPARAM lParam) { AfxMessageBox("test"); } //调用的地方 CWinThread* m_pThrd; //启动 m_pThrd = AfxBeginThread(RUNTIME_CLASS(CTestThread)); // 需要执行线程中的操作时 m_pThrd->PostThreadMessage(WM_TEST,NULL,NULL); // 结束线程 HANDLE hp=m_pThrd->m_hThread; if (hp) { if (WaitForSingleObject(hp, 1) != WAIT_OBJECT_0) { TerminateThread(hp,0); } CloseHandle(hp); }
发表评论
-
Programming Applications for Microsoft Windows - 第七部分 附录
2012-01-20 10:14 698Programming Applications for Mi ... -
windows线程学习
2012-01-20 10:14 557windows线程学习 2010年09月01日 线程(t ... -
WINCE及MOBILE常用代码(转)
2012-01-20 10:14 625WINCE及MOBILE常用代码(转) 2010年06月05 ... -
一个对Winsock完成端口模型封装的类
2012-01-20 10:13 543一个对Winsock完成端口模型封装的类 2011年01月0 ... -
MATLAB安装问题解决方案大集锦
2012-01-19 15:14 819MATLAB安装问题解决方案大集锦 2011年05月08日 ... -
ubuntu编译安装php5 mysql nginx
2012-01-19 15:14 663ubuntu编译安装php5 mysql nginx 201 ... -
MySql安装、优化和安全配置(转)
2012-01-19 15:14 492MySql安装、优化和安全配置(转) 2010年11月21日 ... -
Grub4dos典型菜单文件示范解读
2012-01-19 15:14 841Grub4dos典型菜单文件示 ... -
Grub4dos典型菜单文件示范解读[转贴]
2012-01-19 15:14 511Grub4dos典型菜单文件示范解读[转贴] 2011年07 ... -
C段错误总结
2012-01-17 05:01 465C段错误总结 2012年01月07日 最近一段时间在li ... -
了解学习
2012-01-17 05:01 438了解学习 2011年06月30日 前言 石头说数据同步很 ... -
文本朗读器的设计与制作
2012-01-17 05:01 711文本朗读器的设计与制作 2010年07月29日 文本朗读 ... -
VB9
2012-01-17 05:01 702VB9 2011年05月11日 习题9答案 9-1 ... -
Ajax优于JSF的原因
2012-01-16 03:52 561Ajax优于JSF的原因 2009年 ... -
AS3 框架 不断更新
2012-01-16 03:52 486AS3 框架 不断更新 2011 ... -
RIA
2012-01-16 03:52 395RIA 2010年04月12日 Ja ... -
如何让自己的网站在百度中注册
2012-01-16 03:52 411如何让自己的网站在百度中注册 2009年11月04日 新 ... -
46个Flex和actionscript3开源项目
2012-01-16 03:52 34846个Flex和actionscript3开源项目 2011 ...
相关推荐
上位机的串口通信例子,定时发送接收都没问题。 使用CWinthread实现多线程发送和接收。 刚接触MFC多线程学习的新手会进一步理解多线程。
该程序的功能为利用MFC的多线程类CWinThread实现多线程文件复制。
MFC应用程序为每个CCmdTarget派生类创建一个称为消息映射表的静态数据结构,可将消息映射到对象所对应的消息处理函数上。 (2)设置光标 BeginWaitCursor() 将光标改为沙漏形状; EndWaitCursor() 将光标改回到...
mfc非文档单FormView的使用,C++thunk for 32/64位,CWinThread无GUI工作线程,无GUI定时器,WINAPI调用方式的C++类封装。
MFC的CWinThread线程有两种,一种称为Work线程,一种称为UI线程。一般情况下Work线程与UI线程的区别主要在于UI线程有消息队列(并不是有没有界面,这点要注意,UI线程也是可以没有界面的)
cwinthread的具体实现,窗口线程类
这是一个关于CWinThread以及利用继承自CWinThread使用多线程的程序! 1,尽量使用DECLARE_DYNCREATE,这样能够动态创建。 2,继承自CWinThread,所以可以使用CreateThread()函数进行线程创建,在最开始我被书...
本文实例讲述了VC中CWinThread类以及和createthread API的区别分析,分享给大家供大家参考。具体分析如下: CWinThread CObject └CCmdTarget └CWinThread CWinThread对象代表在一个应用程序内运行的线程。...
从CWnd类派生而来,是MFC视图类和用户视图类的基类。CWnd::Invalidate()或CWnd::InvalidateRect()可以刷新视图。常用函数有: GetDocument(): 视图类对象访问文档类对象中的数据的. OnDraw(): 这个函数有一个指向...
(3)但是,当C++窗口类对象销毁时,与之相关的窗口也将销毁,因为它们之间的纽带m_hWnd已经断了 3、示例---在窗口中显示按钮 (1)CButton按钮类继承于CWnd (2)对于一个CButton对象,在定义之后就可以使用了;但是,...
线程间要处理好同步与通讯,如果用CWinThread好一点,直接是一个线程对象,如果用AfxBeginThread,那必须定个全局函数,或者写个静态函数,一般是传个this指针进去,然后再用这个指针调用本类函数的成员函数,...
第3章 MFC六大关键技术之仿真 MFC类层次结构 Frame 1范例程序 MFC程序的初始化过程 Frame 2范例程序 RTTI(执行期类型识别) 类别型录网与CRuntimeClass DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC宏 Frame 3范例程序 Is...
这是一个简单地介绍MFC用户界面线程的工程,实现了继承自CWinThread类。
MFC UI 线程 ,以及对UI线程发送消息。CWinThread的使用,以及宏 ON_THREAD_MESSAGE ,PostThreadMessage的使用。
第3章 MFC六大关键技术之仿真 MFC类层次结构 Frame 1范例程序 MFC程序的初始化过程 Frame 2范例程序 RTTI(执行期类型识别) 类别型录网与CRuntimeClass DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC宏 Frame 3范例程序 Is...
用CWinThread派生类创建带有窗口的线程 数据交换 使用剪贴板(VC++) 通讯与网络 串行通信(簡易版) 命名管道通讯(簡易版) 部品/控件 文件选择框CFileDialog的个性化 列举可以使用的字模名 自描画按钮 ...
第3章 MFC六大关键技术之仿真 MFC类层次结构 Frame 1范例程序 MFC程序的初始化过程 Frame 2范例程序 RTTI(执行期类型识别) 类别型录网与CRuntimeClass DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC宏 Frame 3范例程序 Is...
CWinThread Locating Threads CCmdTarget Commands for Classes About Message Maps How are Message Maps Created? The BEGIN_MESSAGE_MAP() Macro Inside the Message Map Filling the Holes The END_...