我们知道,Windows以事件驱动方式工作,每个WIN32应用程序都至少包含一个消息队列和一个消息泵。消息队列建立在操作系统提供的内存保留区中,消息泵不断搜寻消息队列,将取得的消息分发给应用程序的各个部分进行处理,这个过程叫做消息循环。基本消息循环如下:

[cpp] view plaincopy

  1. while(GetMessage(&msg,0,0,0))
  2. {
  3. //转换消息参数
  4. TranslateMesssage(&msg);
  5. //分发消息
  6. DispatchMessage(&msg);
  7. }

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() 。以下是该函数的完整定义。

[cpp] view plaincopy

  1. virtual int CWinThread::Run()
  2. {
  3. ASSERT_VALID(this);
  4. //是否要做空闲处理
  5. BOOL bIdle = TRUE;
  6. //用户记录空闲处理已经连接执行的次数
  7. LONG lIdleCount = 0;
  8. //acquire and dispatch messages until a WM_QUIT message is received.
  9. //消息循环
  10. for (;;)
  11. {
  12. //如果空闲状态为真,且消息队列为空,则进行空闲处理
  13. while(bIdle && !::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
  14. {
  15. //PeekMessage()用于检查消息队列是否为空,但并不处理消息
  16. //调用空闲处理程序,如果返回零,说明空闲处理已全部完成
  17. if (!OnIdle(lIdleCount++))
  18. bIdle = FALSE;
  19. }
  20. //空闲处理循环结束,进入消息泵循环
  21. do
  22. {
  23. //调用消息泵,提取消息并分发消息
  24. //如果收到WM_QUIT消息,则退出消息循环
  25. if (!PumpMessage())
  26. return ExitInstance();
  27. //根据刚处理的消息类型,判断是否应该在没有消息到来时立即进行空闲处理
  28. if (IsIdleMessage(&m_msgCur))
  29. {
  30. bIdle = TRUE;
  31. //在重新进行空闲处理前,清空空闲处理的执行次数
  32. lIdleCount = 0;
  33. }
  34. while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
  35. }
  36. ASSERT(FALSE); //不可能执行的语句
  37. }
  38. /*------------- 消息泵函数PumpMessage() ----------------*/
  39. //省略了调试信息的输出功能
  40. BOOL CWinThread::PumpMessage()
  41. {
  42. ASSERT_VALID(this);
  43. //取出消息队列中的第一个消息,直到取得消息,该函数才返回
  44. if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))
  45. {
  46. //收到WM_QUIT消息
  47. return FALSE;
  48. }
  49. //处理消息,但不处理WM_KICKIDLE
  50. if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))
  51. {
  52. //转换虚键消息到字符消息
  53. ::TranslateMessage(&m_msgCur);
  54. //分发消息
  55. ::DispatchMessage(&m_msgCur);
  56. }
  57. return TRUE;
  58. }

阅读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的参数来决定的 ;

一个例子:

[cpp] view plaincopy

  1. class CUIThread : public CWinThread
  2. {
  3. DECLARE_DYNCREATE(CUIThread)
  4. protected:
  5. CUIThread();           // protected constructor used by dynamic creation
  6. // Attributes
  7. public:
  8. // Operations
  9. public:
  10. // Overrides
  11. // ClassWizard generated virtual function overrides
  12. //{{AFX_VIRTUAL(CUIThread)
  13. public:
  14. virtual BOOL InitInstance();
  15. virtual int ExitInstance();
  16. //}}AFX_VIRTUAL
  17. // Implementation
  18. protected:
  19. virtual ~CUIThread();
  20. // Generated message map functions
  21. //{{AFX_MSG(CUIThread)
  22. // NOTE - the ClassWizard will add and remove member functions here.
  23. //}}AFX_MSG
  24. DECLARE_MESSAGE_MAP()
  25. };
  26. //重载函数InitInstance()和ExitInstance()
  27. BOOL CUIThread::InitInstance()
  28. {
  29. CFrameWnd* wnd=new CFrameWnd;
  30. wnd->Create(NULL,"UI Thread Window");
  31. wnd->ShowWindow(SW_SHOW);
  32. wnd->UpdateWindow();
  33. m_pMainWnd=wnd;
  34. return TRUE;
  35. }
  36. //创建新的用户界面线程
  37. void CUIThreadDlg::OnButton1()
  38. {
  39. CUIThread* pThread=new CUIThread();
  40. pThread->CreateThread();
  41. }

请注意以下两点:
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函数中的任务而不执行消息循环,你可以通过这种方法,完成一个工作者线程的功能。

另一个例子:

[cpp] view plaincopy

  1. //.h 文件
  2. #define WM_TEST    WM_USER + 1
  3. class CTestThread : public CWinThread
  4. {
  5. DECLARE_DYNCREATE(CTestThread)
  6. protected:
  7. CTestThread ();
  8. virtual ~CTestThread ();
  9. public:
  10. virtual BOOL InitInstance();
  11. virtual int  ExitInstance();
  12. protected:
  13. afx_msg void OnTest(WPARAM wParam,LPARAM lParam);
  14. DECLARE_MESSAGE_MAP()
  15. };
  16. //.Cpp 文件
  17. #include "stdafx.h"
  18. #include "TestThread.h"
  19. IMPLEMENT_DYNCREATE(CTestThread, CWinThread)
  20. CTestThread::CTestThread()
  21. {
  22. }
  23. CTestThread::~CTestThread()
  24. {
  25. }
  26. BEGIN_MESSAGE_MAP(CTestThread, CWinThread)
  27. ON_THREAD_MESSAGE(WM_TEST,OnTest)
  28. END_MESSAGE_MAP()
  29. BOOL CTestThread::InitInstance()
  30. {
  31. return TRUE;
  32. }
  33. int CTestThread::ExitInstance()
  34. {
  35. return CWinThread::ExitInstance();
  36. }
  37. void CTestThread::OnTest(WPARAM wParam,LPARAM lParam)
  38. {
  39. AfxMessageBox("test");
  40. }
  41. //调用的地方
  42. CWinThread* m_pThrd;
  43. //启动
  44. m_pThrd = AfxBeginThread(RUNTIME_CLASS(CTestThread));
  45. // 需要执行线程中的操作时
  46. m_pThrd->PostThreadMessage(WM_TEST,NULL,NULL);
  47. // 结束线程
  48. HANDLE hp=m_pThrd->m_hThread;
  49. if (hp)
  50. {
  51. if (WaitForSingleObject(hp, 1) != WAIT_OBJECT_0)
  52. {
  53. TerminateThread(hp,0);
  54. }
  55. CloseHandle(hp);
  56. }

Fr:http://blog.csdn.net/flowshell/article/details/6008279

MFC架构之CWinThread类相关推荐

  1. MFC架构之CWnd类

    在Windows系统里,一个窗口的属性分两个地方存放:一部分放在"窗口类"里头,如上所述的在注册窗口时指定:另一部分放在Windows Object本身,如:窗口的尺寸,窗口的位置 ...

  2. MFC中的CAsyncSocket类实现网络通信

    近年来,利用Internet进行网际间通讯,在WWW浏 览.FTP.Gopher这些常规服务,以及在网络电话.多媒体会议等这些对实时性要求严格 的应用中成为研究的热点,而且已经是必需的了.Window ...

  3. MFC中的CString类使用方法指南

    MFC中的CString类使用方法指南 原文出处:codeproject:CString Management [禾路:这是一篇比较老的资料了,但是对于MFC的程序设计很有帮助.我们在MFC中使用字符 ...

  4. 业务中台管理系统、业务中台架构、接口类服务、模型类服务、界面类服务、组件类服务、服务架构、中后台、服务审核、AI服务、位置服务、行业场景服务、企业中台、接口配置、模型配置、数据处理、结构化数据、数据源

    业务中台管理系统.业务中台架构.接口类服务.模型类服务.界面类服务.组件类服务.服务架构.中后台.服务审核.AI服务.位置服务.行业场景服务.企业中台.接口配置.模型配置.数据处理.结构化数据.数据源 ...

  5. MFC 教程【3_CObject类】

    CObject类 CObject是大多数MFC类的根类或基类.CObject类有很多有用的特性:对运行时类信息的支持,对动态创建的支持,对串行化的支持,对象诊断输出,等等.MFC从CObject派生出 ...

  6. 详解数据架构的七类视图(多图+案例)

    数据架构是业务与应用系统建设的桥梁:数据架构基于业务架构(业务模式.流程.规则等)识别出业务数据需求,统一数据语言及操作手段,作为应用系统的应用架构(系统功能.组件.接口等)和技术架构(技术指标.技术 ...

  7. C++写的mfc架构的企业级股票行情软件源码

    C++写的股票行情软件,mfc架构.分为客户端.服务端.数据引擎三部分.代码加资源文件有1个多G,另外还有软件说明文档,指标公式等. 有兴趣的同学可以加QQ:2379624246交流探讨... 主要功 ...

  8. 使用mfc设计长方形的类

    2.使用MFC设计一个长方形类CRectangle,使用对话框输入长方形的长度和宽度,在客户区输出长方形的周长和面积,如图所示. 使用vs创建项目,类型选择"MFC"应用,由于需要 ...

  9. MFC 教程【14_SOCKET类的设计和实现】

    SOCKET类的设计和实现 WinSock基本知识 这里不打算系统地介绍socket或者WinSock的知识.首先介绍WinSock API函数,讲解阻塞/非阻塞的概念:然后介绍socket的使用. ...

最新文章

  1. Action4D:人群和杂物中的在线动作识别:CVPR209论文阅读
  2. ****CI框架源码阅读笔记7 配置管理组件 Config.php
  3. android Handler机制之ThreadLocal详解
  4. 自建SE16N功能,修改数据库表数据
  5. Confluence 6 为空白空间编辑默认主页
  6. 阿里云Https部署网站
  7. 字符串对象数组集合非空判断
  8. 接口测试用python怎么做_请问一下python怎么做接口测试工具?
  9. 简单代码大全_VBA爱好者请进:VBA代码宝概述
  10. linux服务器运维操作命令,Linux服务器运维常用命令列表
  11. Java:装饰设计模式
  12. 加码游戏直播 快手已成腾讯防御今日头条的重要棋子?
  13. 太经典了,不转不行淘宝上面的对话
  14. EXCEL用今天日期减去之前的日期得到结果
  15. 快狗打车冲击港股,同城货运的战役才刚刚开始
  16. iview form表单验证手机号
  17. Python 正则提取字符串中的地区
  18. 编写一个学生类(Students),包括姓名(name)、性别(sex)、学号(num)、语文课(Chinese)、英语课(English)、 数学课(Math)和平均值(avg),方法包括求
  19. 队列Java舞会_stl之队列(舞会) - osc_706v6usl的个人空间 - OSCHINA - 中文开源技术交流社区...
  20. C:\Users\用户名\AppData里面的文件可以删除吗

热门文章

  1. 最详细的FPN论文笔记
  2. 如何优化网站的响应时间
  3. java string.substring 参数,Java,String类中的subString()方法,stringsubstring
  4. ironpython最新版本_Microsoft IronPython2.7.5 最新版
  5. Python大数据系列-01-关系数据库基本运算
  6. maven Web项目添加数据源支持,包括Oracle、Mysql
  7. linux系统中-E,-S,-c的区别和作用(怎么讲代码转化为机器识别的语言)
  8. 用easymock来mock数据
  9. c++11中的for简化用法
  10. Flutter透明度渐变动画FadeTransition实现透明度渐变动画效果