在 MFC 中处理耗时的操作

Posted

技术标签:

【中文标题】在 MFC 中处理耗时的操作【英文标题】:Hanlding time consuming Operations in MFC 【发布时间】:2013-08-11 11:59:42 【问题描述】:

我有一个基于 MFC 的遗留应用程序,目前我无法对其进行太多修改。

有一项功能涉及从/向 INI 文件读取/写入数据。编写时要牢记 ini 文件中的设置数量将非常少。但现在它已经变得非常庞大了。

所以在执行这个任务的时候,大概需要30分钟左右。

问题是当用户点击应用程序时,应用程序被锁定并且窗口窗口显示它没有响应对话框,询问用户是否需要等待应用程序响应或退出。

现在我可以管理时间了。但我不希望窗口显示“无响应”行为。

我认为问题在于,主线程在这个过程中很忙,并且 UI 挂起。我不确定,因为我只是在猜测。

为了处理这个问题,我创建了一个线程并在其中调用这个函数。但在这个线程函数中,我无法调用AfxGetMainWnd(); 函数,因为它返回的是NULL

这将非常有帮助,如果有人请告诉我,如何处理这种情况(离开理想情况下不会发生这种情况)?

也欢迎任何好的建议。

我的另一个想法也是将此代码放在进度条对话框中。---- 欢迎对此进行思考。

谢谢

【问题讨论】:

【参考方案1】:

在 MFC 应用程序中使用线程的技巧是记住只有主线程才能访问所有 GUI 元素。所以,如果你分离一个线程来做一些工作,你需要以某种方式将更新和修改传回主线程,并让它进行 GUI 更新。

最简单的方法是给自己发送一条消息,消息泵在主线程上,所以它总是会接收消息。它真的很简单,一旦你知道了。

因此,创建一些 WM_USER 消息并在需要时从您的线程发送它们并正常处理它们。

【讨论】:

感谢在 MFC 中使用线程的技巧。您能否验证大多数 GUI 框架是这样工作的还是 MFC 的个人框架。 @gbjbaanb WM_USERWM_APP - 1 范围内的消息保留用于控制实现。永远不要将它们重复用于应用内通信;请改用WM_APP + x 消息,这就是它们的用途。 @dear 针对 Windows API 的所有框架都共享单线程 GUI 的限制。虽然并非绝对不可能,但使用 Windows API 实现多线程 GUI 是非常具有挑战性的。 任何单线程的 GUI 都会有同样的限制,主要是因为实现者不会考虑线程问题,所以最好假设在这些情况下所有操作都发生在 UI 线程上。对于故意线程化的 UI,它是不同的,但数量并不多(毕竟,为什么要麻烦 - 你只有 1 个人操作 GUI,线程只是为了微小的利益而使事情复杂化)。【参考方案2】:

从工作线程向 MFC 主线程发布自定义消息的说明如下(参见常见问题解答 12):

http://vcfaq.mvps.org/mfc/index.htm

您应该在工作线程中读取文件。如果您想要一个进度对话框,请将其放在主线程中并向其发布消息以更新进度显示。

【讨论】:

【参考方案3】:

这是我针对这种情况所做的一个技巧。我主要创建基于对话的应用程序来测试各种电气创作或处理数据等。简单的东西,但想要做某种 UI 多任务处理并保持简单。 我添加了这个功能:

void CWhateverApp::doRepaints(void)
    
        MSG msg;
        while (PeekMessage(&msg,NULL,0,0xFFFFFFFF,PM_REMOVE))
        DispatchMessage(&msg);
    

并在我进行任何处理时定期调用它。将其称为每秒 10 倍很好,但即使每秒一次也能提供不错的 UI 体验。另一个技巧:有一个带有处理程序的“取消”按钮,该处理程序在单击时将 bool 设置为 true。 (比如说,调用 bool m_doCancel)。现在,当您开始执行耗时的任务时,请执行以下操作:

m_doCancel= false;

现在做你的任务,经常调用 doRepaints(),然后在调用 doRepaint() 之后检查 bool:

if (m_doCancel == true)  /* stop processing */ 

因此,您可以通过这种方式让用户退出以及处理重绘等。 FWIW! J

【讨论】:

以上是关于在 MFC 中处理耗时的操作的主要内容,如果未能解决你的问题,请参考以下文章

Service可以执行耗时操作吗

iOS开发创建UI的耗时操作处理

主线程不能执行耗时的操作,子线程不能更新Ui

[转]MFC子线程中更新控件内容的两种办法

channelRead对于耗时业务逻辑处理的优化

eventbus能执行耗时操作么