关于mfc异步调用线程的问题

moonk-z 2017-11-29 10:09:34
手头有个小项目,功能不算复杂,就是一个导入导出功能。
函数处理的时候都放在btnClick里面的话,界面会无响应直到完成处理。
因为涉及导出功能,数据量有上万的list和vector的stl,
考虑到这种传参的程度,使用什么方式异步调用会好点?

线程,std::async,io_service->post?
感觉都绕不开这个不小的传参,有没有既能后台处理又能避免这种列表的拷贝的方法?
...全文
586 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
走好每一步 2017-11-30
  • 打赏
  • 举报
回复
可以考虑线程池
赵4老师 2017-11-30
  • 打赏
  • 举报
回复
Multiple Threads in the User Interface http://msdn.microsoft.com/zh-cn/library/ms810439.aspx
moonk-z 2017-11-30
  • 打赏
  • 举报
回复
11L的方法可行,已修改到func类
引用 14 楼 smwhotjay 的回复:
耗时导致ui阻塞了,解决办法就是开线程。 OnClick就开工作线程,修改工作状态为进行中。(比如设置在lable上显示) 工作线程完成了就SendMessage 给窗口 定义个WM_USER+ xxx 为导出完成消息。 窗口消息里把这个消息处理下,弹出窗口提示,什么的,你自己看着办
试了一下这种方式, 但开启线程只能为全局函数(不想这样用)或者静态函数,使用静态函数的话不方便跨类调用sendmessage, 用自己添加的Dlg->SetStaticText()的接口去控制控件。 网上看到说传窗口为参数时,最好不要sendmessage,不太明白为啥。。
引用 15 楼 tajon1226 的回复:
可以考虑线程池
那请问这个线程池是大致怎么个实现法?
csulizhang 2017-11-29
  • 打赏
  • 举报
回复
引用 7 楼 u012072837 的回复:
[quote=引用 5 楼 zhangli00 的回复:] 别总想着拷贝,直接传数据地址就行了,开线程处理是最好的,c++11的新特性里面,开线程非常简单了,而且可以操作类成员变量,存储和读取都非常方便,在同一个类里面的话,传都不用传,直接调用
其实就是不想在同个类里面做,因为发起请求的是界面,想把这块分离到逻辑类里面做[/quote] 分出来也可以呀,你在逻辑类里面开线程,操作逻辑类的数据,UI调用的时候直接通过逻辑类的成员变量实现,这个好像没什么问题吧 我做视音频数据都是这种方法搞得,感觉很方便,而且关键是可以把类实例化成多个对象,各自在各自的线程里面跑,互不干扰,现在除了回调需要全局的或者友元,其他都可以封装在类里面实现了
moonk-z 2017-11-29
  • 打赏
  • 举报
回复
引用 4 楼 zgl7903 的回复:
线程中可以给UI投递消息
请问这里说的线程是指c风格的thread吗?
moonk-z 2017-11-29
  • 打赏
  • 举报
回复
引用 5 楼 zhangli00 的回复:
别总想着拷贝,直接传数据地址就行了,开线程处理是最好的,c++11的新特性里面,开线程非常简单了,而且可以操作类成员变量,存储和读取都非常方便,在同一个类里面的话,传都不用传,直接调用
其实就是不想在同个类里面做,因为发起请求的是界面,想把这块分离到逻辑类里面做
moonk-z 2017-11-29
  • 打赏
  • 举报
回复
引用 3 楼 oyljerry 的回复:
[quote=引用 2 楼 u012072837 的回复:] [quote=引用 1 楼 zgl7903 的回复:] onBnclick 中启动后台线程, 再启动一个定时器监视后台线程运行情况
那这里还是绕不开list的拷贝啊?[/quote] 你只要保证list的生命期,可以传指针等过去。[/quote] 好,我试试
csulizhang 2017-11-29
  • 打赏
  • 举报
回复
别总想着拷贝,直接传数据地址就行了,开线程处理是最好的,c++11的新特性里面,开线程非常简单了,而且可以操作类成员变量,存储和读取都非常方便,在同一个类里面的话,传都不用传,直接调用
zgl7903 2017-11-29
  • 打赏
  • 举报
回复
线程中可以给UI投递消息
oyljerry 2017-11-29
  • 打赏
  • 举报
回复
引用 2 楼 u012072837 的回复:
[quote=引用 1 楼 zgl7903 的回复:] onBnclick 中启动后台线程, 再启动一个定时器监视后台线程运行情况
那这里还是绕不开list的拷贝啊?[/quote] 你只要保证list的生命期,可以传指针等过去。
moonk-z 2017-11-29
  • 打赏
  • 举报
回复
引用 1 楼 zgl7903 的回复:
onBnclick 中启动后台线程, 再启动一个定时器监视后台线程运行情况
那这里还是绕不开list的拷贝啊?
zgl7903 2017-11-29
  • 打赏
  • 举报
回复
onBnclick 中启动后台线程, 再启动一个定时器监视后台线程运行情况
smwhotjay 2017-11-29
  • 打赏
  • 举报
回复
耗时导致ui阻塞了,解决办法就是开线程。 OnClick就开工作线程,修改工作状态为进行中。(比如设置在lable上显示) 工作线程完成了就SendMessage 给窗口 定义个WM_USER+ xxx 为导出完成消息。 窗口消息里把这个消息处理下,弹出窗口提示,什么的,你自己看着办
moonk-z 2017-11-29
  • 打赏
  • 举报
回复
引用 11 楼 zhangli00 的回复:
C++11开线程很简单的 std::thread tt(&ClassName::FunName, this); tt.detach(); 上面就是基本结构,如果你的FunName方法带有参数,就在this后面加参数就行了,如: void FunName(int i,int j); std::thread tt(&ClassName::FunName, this,1,2); 至于detach和join,自己可以百度看看区别,根据需求选择
已用 AfxBeginThread((AFX_THREADPROC)mergeFun, (LPVOID)this, THREAD_PRIORITY_IDLE); 处理,但还是在mfc窗口类中 我试下你的方法。
csulizhang 2017-11-29
  • 打赏
  • 举报
回复
我上面的FunName方法可不是全局方法,是在ClassName这个类里面的成员函数
csulizhang 2017-11-29
  • 打赏
  • 举报
回复
C++11开线程很简单的 std::thread tt(&ClassName::FunName, this); tt.detach(); 上面就是基本结构,如果你的FunName方法带有参数,就在this后面加参数就行了,如: void FunName(int i,int j); std::thread tt(&ClassName::FunName, this,1,2); 至于detach和join,自己可以百度看看区别,根据需求选择
moonk-z 2017-11-29
  • 打赏
  • 举报
回复
引用 9 楼 zhangli00 的回复:
[quote=引用 7 楼 u012072837 的回复:] [quote=引用 5 楼 zhangli00 的回复:] 别总想着拷贝,直接传数据地址就行了,开线程处理是最好的,c++11的新特性里面,开线程非常简单了,而且可以操作类成员变量,存储和读取都非常方便,在同一个类里面的话,传都不用传,直接调用
其实就是不想在同个类里面做,因为发起请求的是界面,想把这块分离到逻辑类里面做[/quote] 分出来也可以呀,你在逻辑类里面开线程,操作逻辑类的数据,UI调用的时候直接通过逻辑类的成员变量实现,这个好像没什么问题吧 我做视音频数据都是这种方法搞得,感觉很方便,而且关键是可以把类实例化成多个对象,各自在各自的线程里面跑,互不干扰,现在除了回调需要全局的或者友元,其他都可以封装在类里面实现了[/quote] 好像也对,那请问下是用什么类型的线程实现的?我只用过最基本的thread join的模式,而且也是全局函数,总觉得这种方式不优雅。
第1章 MFC概述 1 1.1 MFC是一个编程框架 1 1.1.1 封装 1 1.1.2 继承 2 1.1.3 虚拟函数和动态约束 2 1.1.4 MFC的宏观框架体系 2 1.2 MDI应用程序的构成 3 1.2.1 构成应用程序的对象 3 1.2.2 构成应用程序的对象之间的关系 5 1.2.3 构成应用程序的文件 5 第2章 MFC和Win32 9 2.1 MFC Object和Windows Object的关系 9 2.2 Windows Object 12 2.2.1 Windows的注册 12 2.2.2 MFC窗口类CWnd 15 2.2.3 在MFC下创建一个窗口对象 17 2.2.4 MFC窗口的使用 18 2.2.5 在MFC下窗口的销毁 19 2.3 设备描述表 20 2.3.1 设备描述表概述 20 2.3.2 设备描述表在MFC中的实现 22 2.3.3 MFC设备描述表类的使用 24 2.4 GDI对象 25 第3章 CObject类 28 3.1 CObject的结构 28 3.2 CObject类的特性 30 3.3 实现CObject特性的机制 32 3.3.1 DECLARE_DYNAMIC等宏的定义 32 3.3.2 CruntimeClass类的结构与功能 35 3.3.3 动态类信息、动态创建的原理 38 3.3.4 序列化的机制 39 第4章 消息映射的实现 42 4.1 Windows消息概述 42 4.1.1 消息的分类 42 4.1.2 消息结构和消息处理 42 4.2 消息映射的定义和实现 44 4.2.1 MFC处理的三类消息 44 4.2.2 MFC消息映射的实现方法 45 4.2.3 在声明与实现的内部 46 4.2.3.1 消息映射声明的解释 47 4.2.3.2 消息映射实现的解释 49 4.2.4 消息映射宏的种类 51 4.3 CcmdTarget类 54 4.4 MFC窗口过程 55 4.4.1 MFC窗口过程的指定 56 4.4.2 对Windows消息的接收和处理 58 4.4.2.1 从窗口过程到消息映射 59 4.4.2.2 Windows消息的查找和匹配 60 4.4.2.3 Windows消息处理函数的调用 62 4.4.2.4 消息映射机制完成虚拟函数功能的原理 63 4.4.3 对命令消息的接收和处理 64 4.4.3.1 MFC标准命令消息的发送 64 4.4.3.2 命令消息的派发和消息的多次处理 67 4.4.3.3 一些消息处理类的OnCmdMsg的实现 69 4.4.3.4 一些消息处理类的OnCommand的实现 71 4.4.4 对控制通知消息的接收和处理 72 4.4.4.1 WM_COMMAND控制通知消息的处理 72 4.4.4.2 WM_NOTIFY消息及其处理: 73 4.4.4.3 消息反射 74 4.4.5 对更新命令的接收和处理 77 4.4.5.1 实现方法 77 4.4.5.2 状态更新命令消息 78 4.4.5.3 类CCmdUI 79 4.4.5.4 自动更新用户接口对象状态的机制 80 4.5 消息的预处理 82 4.6 MFC消息映射的回顾 83 第5章 MFC对象的创建 85 5.1 MFC对象的关系 85 5.1.1 创建关系 85 5.1.2 交互作用关系 86 5.2 MFC提供的接口 87 5.2.1 虚拟函数接口 87 5.2.2 消息映射方法和标准命令消息 91 5.3 MFC对象的创建过程 94 5.3.1 应用程序中典型对象的结构 94 5.3.1.1 应用程序类的成员变量 95 5.3.1.2 CDocument的成员变量 97 5.3.1.3 文档模板的属性 97 5.3.2 WinMain入口函数 99 5.3.2.1 WinMain流程 99 5.3.2.2 MFC空闲处理 101 5.3.3 SDI应用程序的对象创建 102 5.3.3.1 文档模板的创建 102 5.3.3.2 文件的创建或者打开 103 5.3.3.3 SDI边框窗口的创建 112 5.3.3.4 视的创建 115 5.3.3.5 窗口初始化 116 5.3.3.6 视的初始化 120 5.3.3.7 激活边框窗口(处理WM_ACTIVE) 121 5.3.3.8 SDI流程的回顾 122 5.3.4 MDI程序的对象创建 123 5.3.4.1 有别于SDI的主窗口加载过程 124 5.3.4.2 MDI子窗口、视、文档的创建 125 5.3.4.3 MDI子窗口的初始化和窗口的激活 127 第6章 应用程序的退出 131 6.1 边框窗口对WM_CLOSE的处理 131 6.2 窗口的销毁过程 135 6.2.1 DestroyWindow 135 6.2.2 处理WM_DESTROY消息 136 6.2.3 处理WM_NCDESTROY消息 136 6.3 SDI窗口、MDI主、子窗口的关闭 137 第7章 MFC的DLL 139 7.1 DLL的背景知识 139 7.2 调用约定 141 7.2.1 MFC的DLL应用程序的类型 142 7.3 DLL的几点说明 143 7.4 输出函数的方法 145 第8章 MFC的进程和线程 148 8.1 Win32的进程和线程概念 148 8.2 Win32的进程处理简介 148 8.2.1 进程的创建 148 8.2.2 进程的终止 149 8.3 Win32的线程 150 8.3.1 线程的创建 150 8.3.2 线程的终止 150 8.3.3 线程局部存储 151 8.4 线程同步 152 8.4.1 同步对象 152 8.4.2 等待函数 153 8.5 MFC线程处理 154 8.5.1 创建用户界面线程 155 8.5.2 创建工作者线程 155 8.5.3 AfxBeginThread 155 8.5.4 CreateThread和_AfxThreadEntry 157 8.5.5 线程的结束 160 8.5.6 实现线程的消息循环 161 第9章 MFC的状态 163 9.1 模块状态 163 9.2 模块、进程和线程状态的数据结构 164 9.2.1 层次关系 164 9.2.2 CNoTrackObject类 166 9.2.3 AFX_MODULE_STATE类 166 9.2.4 _AFX_BASE_MODULE_STATE 169 9.2.5 _AFX_THREAD_STATE 169 9.2.6 AFX_MODULE_THREAD_STATE 171 9.3 线程局部存储机制和状态的实现 172 9.3.1 CThreadSlotData和_afxThreadData 173 9.3.1.1 CThreadSlotData的定义 173 9.3.1.2 CThreadSlotData的一些数据成员 174 9.3.1.3 _afxThreadData 175 9.3.2 线程状态_afxThreadState 176 9.3.3 进程模块状态afxBaseModuleState 178 9.3.4 状态对象的创建 180 9.3.4.1 状态对象的创建过程 180 9.3.4.2 创建过程所涉及的几个重要函数的算法 183 9.4 管理状态 184 9.4.1 模块状态切换 184 9.4.2 扩展DLL的模块状态 186 9.4.2.1 _AFX_EXTENSION_MODULE 187 9.4.2.2 扩展DLL的初始化函数 188 9.4.3 核心MFC DLL 190 9.4.4 动态链接的规则DLL的模块状态的实现 190 9.5 状态信息的作用 192 9.5.1.1 模块信息的保存和管理 192 9.5.2 MFC资源、运行类信息的查找 193 9.5.3 模块信息的显示 194 9.5.4 模块-线程状态的作用 196 9.5.4.1 只能访问本线程MFC对象的原因 196 9.5.4.2 实现MFC对象和Windows对象之间的映射 196 9.5.4.3 临时对象的处理 199 9.6 状态对象的删除和销毁 199 第10章 内存分配方式和调试机制 202 10.1 M内存分配 202 10.1.1 内存分配函数 202 10.1.2 C++的new 和 delete操作符 204 10.2 调试手段 204 10.2.1 C运行库提供和支持的调试功能 204 10.2.2 MFC提供的调试手段 205 10.2.3 内存诊断 208 第11章 MFC下的文件类 210 11.1 文件操作的方法 210 11.2 MFC的文件类 210 11.2.1 CFile的结构 211 11.2.1.1 CFile定义的枚举类型 211 11.2.1.2 CFile的其他一些成员变量 212 11.2.1.3 CFile的成员函数 212 11.2.2 CFile的部分实现 213 11.2.3 CFile的派生类 215 第12章 对话框和对话框类CDialog 217 12.1 模式和无模式对话框 217 12.1.1 模式对话框 217 12.1.2 无模式对话框 218 12.2 对话框的MFC实现 219 12.2.1 CDialog的设计和实现 219 12.2.1.1 CDialog的成员变量 219 12.2.1.2 CDialog的成员函数: 219 12.2.2 MFC模式对话框的实现 220 12.2.2.1 MFC对话框过程 220 12.2.2.2 模式对话框窗口过程 221 12.2.2.3 使用原对话框窗口过程作消息的缺省处理 225 12.2.2.4 Dialog命令消息和控制通知消息的处理 226 12.2.2.5 消息预处理和Dialog消息 228 12.2.2.6 模式对话框的消息循环 229 12.2.3 对话框的数据交换 233 12.2.3.1 数据交换的方法 233 12.2.3.2 CDataExchange 234 12.2.3.3 数据交换和验证函数 236 12.2.3.4 UpdateData函数 239 12.3 无模式对话框 240 12.3.1 CScrollView 240 12.3.2 CFormView 242 12.3.2.1 CFormView的创建 243 12.3.2.2 CFormView的消息预处理 245 12.3.2.3 CFormView的输入焦点 247 第13章 MFC工具条和状态栏 248 13.1 Windows控制窗口 248 13.2 MFC的工具条和状态栏类 249 13.2.1 控制窗口的创建 251 13.2.1.1 PreCreateWindow 251 13.2.1.2 控制条的窗口创建 253 13.2.2 控制条的销毁 259 13.2.3 处理控制条的位置 259 13.2.3.1 计算控制条位置的过程和算法 259 13.2.3.2 CFrameWnd的虚拟函数RecalcLayout 260 13.2.3.3 CWnd的成员函数RepositionBars 262 13.2.4 工具条、状态栏和边框窗口的接口 265 13.2.4.1 应用程序在状态栏中显示信息 265 13.2.4.2 状态栏显示菜单项的提示信息 268 13.2.4.3 控制条的消息分发处理 270 13.2.4.4 Tooltip 275 13.2.4.5 禁止和允许 279 13.2.4.6 显示或者隐藏工具栏和状态栏 285 13.2.5 泊位和漂浮 286 第14章 SOCKET类的设计和实现 288 14.1 WinSock基本知识 288 14.1.1 WinSock API 288 14.1.2 Socket的使用 290 14.2 MFC对WinSockt API的封装 291 14.2.1 CAsyncSocket 291 14.2.2 socket对象的创建和捆绑 292 14.2.3 异步网络事件的处理 296 14.3 CSocket 297 14.4 CSocketFile 299
网络编程,当然要用到Windows Socket(套接字)技术。Socket相关的操作由一系列API函数来完成,比如socket、bind、listen、connect、accept、send、sendto、recv、recvfrom等。调用这些API函数有一定的先后次序,有些函数的参数还比较复杂,对于开发者来说,不是很好用。于是,微软的MFC提供了两个类:CAsyncSocket和CSocket,极大地方便了Socket功能的使用。   CAsyncSocket类在较低层次上封装了Windows Socket API,并且通过内建一个(隐藏的)窗口,实现了适合Windows应用的异步机制(Windows Socket API默认情况下工作在阻塞模式,不方便直接在消息驱动的Windows程序上使用)。CSocket类从CAsyncSocket类派生,进一步简化了Socket功能的应用。不过很遗憾,正因为这两个类都内建了一个窗口,它们并不是线程安全的(thread-safe);如果要在多线程环境下应用Socket功能,建议自行封装Socket API函数。 基于TCP的socket编程的服务器端程序流程如下: 1、创建套接字 2、将套接字绑定到一个本地地址和端口号上(bind) 3、将套接字设为监听模式,准备接受客户请求(listen) 4、等待客户请求,请求到来时接受请求,建立链接,并返回 一个新的基于此次通信的套接字(accept) 5、用返回的套接字和客户端进行通信(send、recv) 6、返回,等待另一客户请求 7、关闭套接字 基于TCP的socket编程的客户端程序流程如下: 1、创建套接字 2、向服务器端发送请求(connect) 3、和服务器端进行通信(send、recv) 4、关闭套接字 基于UDP的socket编程的服务器端程序流程如下: 1、创建套接字 2、将套接字绑定到本地地址和端口号上(bind) 3、等待接收数据(recvfrom) 4、关闭套接字 基于UDP的socket编程的客户端程序流程如下: 1、创建套接字 2、和服务器端进行通信(sendto) 3、关闭套接字 异步方式指的是发送方不等接收方响应,便接着发下个数据包的通信方式;而同步指发送方发出数据后,等收到接收方发回的响应,才发下一个数据包的通信方式。   阻塞套接字是指执行此套接字的网络调用时,直到成功才返回,否则一直阻塞在此网络调用上,比如调用recv()函数读取网络缓冲区中的数据,如果没有数据到达,将一直挂在recv()这个函数调用上,直到读到一些数据,此函数调用才返回;而非阻塞套接字是指执行此套接字的网络调用时,不管是否执行成功,都立即返回。比如调用recv()函数读取网络缓冲区中数据,不管是否读到数据都立即返回,而不会一直挂在此函数调用上。在实际Windows网络通信软件开发中,异步非阻塞套接字是用的最多的。平常所说的C/S(客户端/服务器)结构的软件就是异步非阻塞模式的。   对于这些概念,初学者的理解也许只能似是而非,我将用一个最简单的例子说明异步非阻塞Socket的基本原理和工作机制。目的是让初学者不仅对Socket异步非阻塞的概念有个非常透彻的理解,而且也给他们提供一个用Socket开发网络通信应用程序的快速入门方法。操作系统是Windows 98(或NT4.0),开发工具是Visual C++6.0。   MFC提供了一个异步类CAsyncSocket,它封装了异步、非阻塞Socket的基本功能,用它做常用的网络通信软件很方便。但它屏蔽了Socket的异步、非阻塞等概念,开发人员无需了解异步、非阻塞Socket的原理和工作机制。因此,建议初学者学习编网络通信程序时,暂且不要用MFC提供的类,而先用Winsock2 API,这样有助于对异步、非阻塞Socket编程机制的理解。

15,979

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧