基于MFC的多线程编程实例

本文详细介绍MFC中AfxBeginThread函数的使用方法,包括工作者线程与用户界面线程的区别,通过实例演示如何创建与控制线程,实现线程间的通信。

————————————————
版权声明:本文为CSDN博主「三公子Tjq」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/naibozhuan3744/article/details/78754614

(本文的第三部分为本人自己添加内容,算是看完博文的笔记)
MFC的多线程函数AfxBeginThread包含了两种版本,一种是工作者线程,一种是用户界面线程。本文主要讲解的是工作者线程的用法和提供一个实例。如果需要用户界面的用法,可以参考这篇文章http://www.cnblogs.com/lidabo/p/3489639.html。

一、工作者线程AfxBeginThread用法

1.1首先比较工作者线程函数和用户界面线程函数的异同
1.1.1工作者线程AfxBeginThread原型:(必看)
CWinThread*
AFXAPI AfxBeginThread(
AFX_THREADPROC pfnThreadProc,
LPVOID pParam,
int nPriority,
UINT nStackSize,
DWORD dwCreateFlags,
LPSECURITY_ATTRIBUTES lpSecurityAttrs)
各个参数功能详解如下:
参数1:线程的入口函数,返回值一定为UINT,函数参数为:LPVOID,例如: UINT MyThreadFunction( LPVOID pParam );

参数2 :传递入线程的参数,注意它的类型为:LPVOID,所以我们可以传递一个结构体入线程.
参数3:指定线程优先级,如果为0,则与创建该线程的线程相同;
参数4:指定线程的堆栈大小,如果为0,则与创建该线程的线程相同;
参数5:创建标识,如果是CREATE_SUSPENDED,则在悬挂状态创建线程,在线程创建后线程挂起,否则线程在创建后开始线程的执行。
参数6:表示线程的安全属性,NT下有用。
1.1.2用户界面线程AfxBeginThread原型:(可以不看)
CWinThread*
AFXAPI AfxBeginThread(
CRuntimeClass* pThreadClass,
intnPriority,
UINTnStackSize,
DWORDdwCreateFlags,
LPSECURITY_ATTRIBUTES lpSecurityAttrs)
各个参数功能详解如下:
参数1:是从CWinThread派生的RUNTIME_CLASS类;
参数2:指定线程优先级,如果为0,则与创建该线程的线程相同;
参数3:指定线程的堆栈大小,如果为0,则与创建该线程的线程相同;
参数4:是一个创建标识,如果是CREATE_SUSPENDED,则在悬挂状态创建线程,在线程创建后线程挂起,否则线程在创建后开始线程的执行。
参数5:表示线程的安全属性,NT下有用。

二、工作者线程AfxBeginThread函数用法实例

调用工作者线程AfxBeginThread函数的具体步骤如下所示:
2.1首先创建基于对话框的MFC工程后,在主对话框添加一个按钮控件(命名为打开线程),两个编辑框控件(功能是分别显示主线程状态和子线程状态),如下图所示:
在这里插入图片描述
2.2双击【打开线程】按钮函数,在按钮事件处理函数中,添加如下代码(可直接copy,修改一下两个对应编辑框ID和一个按钮ID就行)

if (ThreadFlag)
       {
              //关闭线程函数
              ThreadFlag = FALSE;//线程标识一定要放在最前面,否则函数执行会出现莫名其妙错误!!!
              GetDlgItem(IDC_BUTTON_TEST)->SetWindowTextA("打开线程");//AfxBeginThread线程的关闭,利用函数执行完毕后,自动返回,然后创建的线程也跟着关闭,对应资源也跟着释放。IDC_BUTTON_TEST按钮ID号,要修改成按钮上的ID号
              return;
       }
       else
       {
              //创建线程函数
              ThreadFlag = TRUE;//线程标识一定要放在最前面,否则函数执行会出现莫名其妙错误!!!
              HANDLE hMultiThread = AfxBeginThread(ChildThread,
/*(LPVOID)*/this,
THREAD_PRIORITY_IDLE);//ChildThread线程函数入口(返回值为UINT,参数为LPVIOD
 lParam)  this入口点函数参数  THREAD_PRIORITY_IDLE设置优先级 
参数4、5分别指定线程的堆栈大小(0:与参将线程相同)、创建标识(创建后悬挂CREATE_SUSPENDED或者立即执行)、安全属性,含义同用户界面线程
              GetDlgItem(IDC_EDIT_MAIN)->SetWindowTextA("主线程开启");  
//IDC_EDIT_MAIN主线程对话框ID号,要修改成自己的主线程对话框ID号
              GetDlgItem(IDC_BUTTON_TEST)->SetWindowTextA("关闭线程");//IDC_BUTTON_TEST子线程对话框ID号,要修改成自己的子线程对话框ID号
              return;
       }

2.3在按钮函数的上面,添加如下代码:(可直接copy,修改一下对应编辑框ID就行)

UINT ChildThread(LPVOID
lParam)//多线程入口点函数,相当于另一个main,CPU或同时执行MFC的主线程和ChildThread线程函数
{
       CMFCMultiThreadTest1Dlg* pDlg = (CMFCMultiThreadTest1Dlg*)lParam;//创建一个指向主对话框的句柄
       CStringstr;
       intThreadCound = 1;
       while(pDlg->ThreadFlag)
       {
              str.Format(_T("子线程开启第%d次"),
 ThreadCound++);//
              pDlg->GetDlgItem(IDC_EDIT_CHILD)->SetWindowTextA(str);//设置子对话框显示str的内容,pDlg指向主对话框类入口点。编辑框和按钮控件都在主对话框上,所以可以通过获取主对话框类上的句柄,调用和修改主对话框上按钮控件类和编辑框类。IDC_EDIT_CHILD子线程编辑框的ID,需要修改为自己子对话框ID号
              Sleep(1000);//定时1秒钟
       }
       return0;
}

2.4在主对话框Dlg头文件,加入如下代码:(注意:是创建工程主对话框下的头文件,带有Dlg的.比如我创建的工程命名为CMFCMultiThreadTest1Dlg,则主对话框头文件是CMFCMultiThreadTest1Dlg.h)

int ThreadFlag;//线程开启和关闭标志值,是全局变量

2.5在CMFCMultiThreadTest1Dlg::OnInitDialog()下面,添加如下代码:

ThreadFlag = FALSE;

三、函数编译执行后,得到的结果如下图所示:
程序运行后的图
在这里插入图片描述
点击【打开线程】按钮后的图

在这里插入图片描述
点击【关闭按钮】后的图
在这里插入图片描述

思路总结

首先,创建一个对话框
其次,在按钮触发事件中填入线程的开关判断,并附带线程的开关操作
最后,编写控制函数,实现线程中的具体功能

目 录 译者序 前言 第一部分 基础知识 第1章 窗口 2 1.1 窗口和API环境 2 1.1.1 三种类型窗口 2 1.1.2 客户区和非客户区 3 1.2 窗口和MFC环境 4 1.3 怎样应用MFC创建一个窗口 5 1.4 怎样使用MFC销毁一个窗口 9 1.4.1 捆绑到一个已有的窗口 9 1.4.2 窗口类 10 1.4.3 窗口进程 10 1.5 怎样使用MFC创建一个窗口类 11 1.5.1 使用AfxRegisterWndClass () 函数注册一个窗口类 11 1.5.2 使用AfxRegisterClass ()函数 创建一个窗口类 12 1.6 怎样销毁一个MFC窗口类 14 1.7 厂商安装的窗口类 14 1.8 其他类型窗口 15 1.9 桌面窗口 16 1.10 小结 16 第2章 类 18 2.1 基类 18 2.1.1 CObject 18 2.1.2 CCmdTarget 19 2.1.3 CWnd 19 2.2 应用程序、框架、文档和视图类 19 2.2.1 CWinApp(O/C/W) 20 2.2.2 CView (O/C/W) 21 2.3 其他用户界面类 22 2.3.1 通用控件类 23 2.3.2 菜单类 23 2.3.3 对话框类 24 2.3.4 控制条类 24 2.3.5 属性类 25 2.4 绘图类 25 2.4.1 设备环境类 25 2.4.2 图形对象类 25 2.5 文件类 26 2.6 数据库类 26 2.6.1 ODBC类 26 2.6.2 DAO类 27 2.7 数据集类 27 2.8 其他数据类 27 2.9 通信类 28 2.10 其他类 29 2.11 小结 31 第3章 消息处理 32 3.1 发送或寄送一个消息 32 3.1.1 发送一个消息 32 3.1.2 寄送一个消息 32 3.1.3 发送一个消息与寄送一个消息 的比较 32 3.2 怎样使用MFC发送一个消息 33 3.3 怎样用MFC寄送一个消息 33 3.4 三种类型的消息 34 3.4.1 窗口消息 34 3.4.2 命令消息 34 3.4.3 控件通知 34 3.5 MFC怎样接收一个寄送的消息 36 3.6 MFC怎样处理一个接收到的消息 36 3.7 处理用户界面的对象 44 3.8 创建自定义窗口消息 45 3.8.1 静态分配的窗口消息 45 3.8.2 动态分配的窗口消息 46 3.9 重定向消息 47 3.9.1 子分类和超分类 47 3.9.2 用MFC子分类窗口 48 3.9.3 重载OnCmdMsg ( ) 49 3.9.4 使用SetWindowsHookEx ( ) 49 3.9.5 使用SetCapture ( ) 49 3.9.6 专有的消息泵 50 3.10 小结 50 第4章 绘图 51 4.1 设备环境 51 4.2 在MFC环境中创建一个设备环境 52 4.2.1 屏幕 52 4.2.2 打印机 53 4.2.3 内存 54 4.2.4 信息 54 4.3 绘图例程 55 4.3.1 画点 55 4.3.2 画线 55 4.3.3 画形状 55 4.3.4 形状填充和翻转 55 4.3.5 滚动 56 4.3.6 绘制文本 56 4.3.7 绘制位图和图标 56 4.4 绘图属性 56 4.4.1 设备环境属性 57 4.4.2 画线属性 58 4.4.3 形状填充属性 58 4.4.4 文本绘制属性 58 4.4.5 映像模式 59 4.4.6 调色板属性 62 4.4.7 混合属性 62 4.4.8 剪裁属性 63 4.4.9 位图绘制属性 64 4.5 元文件和路径 65 4.5.1 元文件 65 4.5.2 路径 66 4.6 颜色和调色板 66 4.6.1 抖动色 67 4.6.2 未经抖动色 67 4.6.3 系统调色板 67 4.6.4 使用系统调色板 68 4.6.5 动画色 71 4.7 控制什么时候在哪里绘图 71 4.7.1 处理WM_PAINT 71 4.7.2 只绘制被无效化的区域 72 4.7.3 处理WM_DRAWITEM 72 4.7.4 在其他时间绘图 73 4.8 小结 74 第二部分 用户界面实例 第5章 应用程序与环境 76 5.1 例1 规划MFC应用程序 76 5.2 例2 用AppWizard创建一个MFC 应用程序 79 5.3 例3 用ClassWizard创建一个类 83 5.4 例4 初始化应用程序屏幕 84 5.5 例5 保存应用程序屏幕 86 5.6 例6 处理命令行选项 88 5.7 例7 动态改变应用程序图标 91 5.8 例8 提示用户优先选项 93 5.9 例9 保存和恢复用户优先选项 97 5.10 例10 终止应用程序 100 5.11 例11 创建一个启动窗口 101 第6章 菜单 107 6.1 例12 使用菜单编辑器 107 6.2 例13 添加一个菜单命令处理函数 109 6.3 例14 根据当前可视文档动态改 变菜单 110 6.4 例15 启用和禁用菜单命令 111 6.5 例16 复选标记菜单命令 112 6.6 例17 单选标记菜单命令 113 6.7 例18 动态修改菜单 114 6.8 例19 动态修改系统菜单 116 6.9 例20 触发一个菜单命令 117 6.10 例21 创建弹出式菜单 117 第7章 工具栏和状态栏 120 7.1 例22 使用工具栏编辑器 120 7.2 例23 启用和禁用工具栏按钮 122 7.3 例24 为工具栏按钮添加字 123 7.4 例25 非标准工具栏大小 128 7.5 例26 保持工具栏按钮按下 129 7.6 例27 保持工具栏按钮组中 一个按钮按下 130 7.7 例28 为工具栏添加非按钮控件 131 7.8 例29 修改应用程序的状态栏 136 7.9 例30 更新状态栏窗格 138 7.10 例31 为状态栏添加其他控件 139 第8章 视图 145 8.1 例32 滚动视图 145 8.2 例33 改变鼠标光标形状 147 8.3 例34 沙漏光标 148 8.4 例35 窗体视图 149 8.5 例36 列表视图 152 8.6 例37 动态分割一个视图 163 第9章 对话框和对话条 166 9.1 例38 使用对话框编辑器 166 9.2 例39 创建一个对话框类 168 9.3 例40 模式对话框 170 9.4 例41 无模式对话框 171 9.5 例42 在无模式对话框的控件间 切换焦点 172 9.6 例43 对话框中的动画 173 9.7 例44 消息框 174 9.8 例45 对话条 176 第10章 控件窗口 182 10.1 例46 在任意位置创建一个控 件窗口 182 10.2 例47 用子分类定制一个通用 控件窗口 183 10.3 例48 用超分类定制一个通用 控件窗口 188 10.4 例49 在按钮上放置位图 190 10.5 例50 动态填充一个组合框 192 10.6 例51 排序一个列表控件 194 10.7 例52 分隔线控件 196 第11章 绘图 198 11.1 例53 绘制图形 198 11.2 例54 绘制文本 201 11.3 例55 从任意位置装入一个图 标并绘制 203 11.4 例56 从任意位置装入一个位 图和绘制一个位图 204 11.5 例57 从文件中创建一个位图 206 11.6 例58 创建一个自绘位图 211 第三部分 内部处理实例 第12章 消息 215 12.1 例59 添加消息处理函数或重 载MFC类 216 12.2 例60 添加命令范围消息处理函数 219 12.3 例61 重定向命令消息 221 12.4 例62 创建自己的窗口消息 222 第13章 文件、串行化和数据库 225 13.1 例63 访问二进制文件 225 13.2 例64 访问标准I/O文件 227 13.3 例65 访问内存文件 228 13.4 例66 在数据类中实现串行化 229 13.5 例67 串行化SDI或MDI文档 235 13.6 例68 按要求串行化 240 13.7 例69 透明地更新串行化的文档 242 13.8 例70 串行化多态类 246 13.9 例71 串行化数据集 248 13.10 例72 访问ODBC数据库 252 13.11 例73 访问DAO数据库 257 第14章 杂类 263 14.1 例74 剪切、拷贝和粘贴文本 数据 263 14.2 例75 剪切、拷贝、粘贴多信 息文本数据 268 14.3 例76 剪切、拷贝和粘贴二进制 数据 273 14.4 例77 数组函数 280 14.5 例78 列表函数 281 14.6 例79 映像函数 283 14.7 例80 系统键盘输入 285 14.8 例81 时间 288 第四部分 打包实例 第15章 库 291 15.1 例82 静态链接C/C++库 291 15.2 例83 动态链接C/C++库 295 15.3 例84 动态链接MFC扩展类库 300 15.4 例85 资源库 303 第五部分 附录 附录A 控件窗口风格 305 附录B 消息、控件通知和消息映像宏 323 附录C 访问其他应用程序类 328 附录D 开发中注意事项 330 附录E MFC快速参考指南 339
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值