【问题标题】:wxWidgets - multitasking with single threadwxWidgets - 单线程多任务处理
【发布时间】:2012-12-05 03:17:30
【问题描述】:

我有一个使用 wxWidgets 创建的 GUI 应用程序。作为功​​能的一部分,我必须在操作 GUI 窗口的同时运行“任务”。例如,我可能会运行代码:

long currentTime = wxGetLocalTime();
long stopTime = wxGetLocalTime() + 3;
while (wxGetLocalTime() != stopTime) {}
wxMessageBox("DONE IN APP");

在这 3 秒的持续时间内,我的应用程序基本上会被冻结,直到显示 wxMessageBox。有没有办法让这个在后台运行而不使用多个线程?它给我正在开发的应用程序带来了问题。

我想知道是否可以使用某些类型的事件处理。非常感谢任何形式的帮助。

【问题讨论】:

  • 为什么要求你不想使用后台线程?
  • GUI 非常密集,所以希望保持单线程。在规范中更倾向于单线程。

标签: c++ multithreading background wxwidgets multitasking


【解决方案1】:

试试这个:

long currentTime = wxGetLocalTime();
long stopTime = wxGetLocalTime() + 3;
while (wxGetLocalTime() != stopTime) {
   wxYield();
}
wxMessageBox("DONE IN APP");

【讨论】:

  • 只要添加另一个 GUI 组件不会干扰 wxMessageBox 的调用,此方法就可以正常工作。有没有办法让它添加另一个组件(如果它正在添加,那就是),然后,无论经过的时间如何,都会显示 wxMessageBox?感谢您的帮助。
  • 我不明白。 '添加另一个 GUI 组件......干扰 wxMessageBox 的调用。'你在添加什么以这种方式干扰?
【解决方案2】:

在 GUI wx 应用程序中运行耗时任务有 3 种方法:

  1. 到目前为止,最优选的是使用不同的线程。应用程序“非常密集的 GUI”的解释对我来说真的没有任何意义,我认为如果它的 GUI 强度(无论它是什么)阻止您使用后台工作线程,您应该认真重新考虑您的程序设计。如果您确实使用这种方法,它非常简单,但要特别注意线程/程序终止问题。特别是,您需要等待线程完成(如果运行时间不长,则可以接受)或在退出程序之前显式取消它。

  2. 只要没有其他要处理的事件,就使用EVT_IDLE 事件来执行您的任务。这对于可以分解成足够小块的小任务来说并不算太糟糕,因为您需要能够在处理程序中恢复处理。不要忘记致电event.RequestMore() 以继续获取空闲事件,即使其他情况没有发生。

  3. 最糟糕和最危险的是按照另一个答案的建议致电wxYield()。这最初看起来很简单,但您后悔这样做,因为这会在您的代码中造成极其难以调试的重入问题。如果你确实使用了它,你需要自己去防止任何地方的重入,你应该真正了解这个函数到底是做什么的。

【讨论】:

  • 线程当然不是“最首选”的解决方案。正如 Richard Hipp 所说“线程是邪恶的 - 避免它们”sqlite.org/faq.html#q6
  • 在 wxWidgets GUI 应用程序开发的上下文中,从各个角度来看,线程是迄今为止最好的解决方案。我不会在此评论中解释原因,但我可以说我有超过 15 年的经验来证明这一点。
  • “线程是邪恶的”是我听过的最不专业的方法。我接受线程不是没有问题的,就像 C++ 中的动态内存分配一样。线程是许多技术的支柱,例如“无线程”node.js。 ^_^ 如果您使用清晰分离的 GUI / 工作线程设置,您可以编写一个非常干净和合乎逻辑的应用程序。无论如何,您不需要破坏您的算法以使其进入 EVT_IDLE 的多个调用或处理 wxYield。 “非常密集的 GUI”对我来说只是“耦合”,也许可以改进?
  • 你知道理查德·希普是谁吗?在你称他为“不专业”之前,也许你应该检查一下。
【解决方案3】:

我知道这已经晚了,但是......

我已经成功地使用了 YEARS 的 EVT_IDLE 方法(最初是在 90 年代使用 Motif)。主要思想是将你的任务分解成小块,每块都调用下一块(想想链表)。执行此操作的机制是使用 CallAfter() 方法(当然是使用 C++)。您只需将“CallAfter()”作为该部分的最后一步,这将允许 GUI 主循环运行另一个迭代,并可能在调用您的下一个部分之前更新 GUI 元素等。请记住保持碎片小。

使用后台线程确实不错,但可能比您想象的要复杂......最终。只要您知道您在后台处理的数据不会被其他任何东西触及/查看,就可以了。如果您知道是这种情况,那么这就是要走的路。此方法允许 GUI 在后台计算期间保持完全响应(调整窗口大小/移动窗口等)

在任何一种情况下,都不要忘记将适当的 GUI 元素脱敏作为第一步,这样您就不会意外地多次启动相同的后台任务(例如,意外地连续多次单击按钮以启动后台线程)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-29
    • 2015-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-28
    • 1970-01-01
    • 2012-02-12
    相关资源
    最近更新 更多