关于Windows窗体中多线程和后台工作线程的一些问题

时间:2012-12-22 08:33:31

标签: c++ winforms multithreading c++-cli backgroundworker

我遇到了在使用C ++的Windows窗体GUI应用程序中使用多线程的需要。根据我对该主题的研究,似乎后台工作者线程是我的目的。根据示例代码,我有

System::Void backgroundWorker1_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) 
{
    BackgroundWorker^ worker = dynamic_cast<BackgroundWorker^>(sender);
    e->Result = SomeCPUHungryFunction( safe_cast<Int32>(e->Argument), worker, e );
}

然而,有一些事情我需要直截了当地弄明白

  • 后台工作线程会让我的多线程生活更轻松吗?
  • 为什么我需要e-&gt;结果?
  • 传递给backgroundWorker1_DoWork函数的参数是什么?
  • 参数safe_cast(e-&gt; Argument)的目的是什么?
  • 我的CPUHungryFunction()应该做什么?
  • 如果我的CPUHungryFunction()有一个无限循环的while循环怎么办?
  • 我可以控制工作线程获得的处理器时间吗?
  • 可以更具体地控制循环在设定时间内循环的次数吗?当我只需要每秒循环30次时,我不想每秒使用cpu循环1000次。 *是否有必要控制GUI更新的速率?

2 个答案:

答案 0 :(得分:3)

  

后台工作线程会让我的多线程生活更轻松吗?

是的,非常如此。它可以帮助您处理无法从工作线程更新UI的事实。特别是ProgressChanged事件允许您显示进度,RunWorkerCompleted事件允许您使用工作线程的结果来更新UI,而无需处理跨线程问题。

  

为什么我需要e-&gt;结果?

将您所做工作的结果传回UI线程。您可以在RunWorkerCompleted事件处理程序中获取值,e-&gt; Result属性。然后,您可以使用结果更新UI。

  

传递给函数的参数是什么?

告诉工作线程要做什么,它是可选的。否则与将参数传递给任何方法相同,只是因为你没有选择参数而更加尴尬。您通常会从UI传递某种值,例如,如果需要传递多个辅助类,请使用一个小助手类。总是倾向于试图在工人中获取UI值,这非常麻烦。

  

我的CPUHungryFunction()应该做些什么?

当然要烧掉CPU周期。或者通常做一些需要很长时间的事情,比如dbase查询。哪个不会烧掉CPU周期,但是在等待结果时需要太长时间才能让UI线程死掉。粗略地说,每当你需要做一些超过一秒钟的事情时,你应该在工作线程而不是UI线程上执行它。

  

如果我的CPUHungryFunction()有一个无限循环的while循环怎么办?

然后你的工人永远不会完成,也永远不会产生结果。这可能有用,但并不常见。您通常不会为此使用BGW,只是将其IsBackground属性设置为true的常规Thread。

  

我可以控制工作线程获得的处理器时间吗?

你可以通过调用Thread.Sleep()来人为地减慢速度。这不是常见的事情,启动工作线程的重点是做工作。睡眠的线程以非生产性的方式使用昂贵的资源。

  

可以更具体地控制循环在设定时间内循环的次数吗?当我只需要每秒循环30次时,我不想每秒使用cpu循环1000次。

同上,你必须睡觉。这样做是通过执行循环30次然后再睡一秒钟。

  

是否有必要控制更新GUI的速率?

是的,这非常重要。 ReportProgress()可以是一个消防软件,每秒产生数千个UI更新。当UI线程无法跟上该速率时,您可以轻松解决此问题。你会注意到,UI线程停止处理它的常规职责,比如绘制UI和响应输入。因为它不断处理另一个调用请求来运行ProgressChanged事件处理程序。副作用是UI看起来冻结,你得到了一个确切的问题,你试图用工人解决。它实际上并没有被冻结,只是看起来那样,它仍在运行事件处理程序。但是你的用户不会看到差异。

要记住的一件事是ReportProgress()只需要保持人眼的快乐。其中发现的更新频率高于每秒20次。除此之外,它只是变成一种难以理解的模糊。所以不要把时间花在那些无用的UI更新上。你也会自动避免火管问题。调整更新速率是您必须编程的,它不是内置于BGW中。

答案 1 :(得分:1)

我会尽力回答你的问题

  1. DoWork是一种无效方法(需要这样)。 DoWork也会执行 在与调用者不同的线程中,所以你需要有一个 将某些东西返回给调用线程的方法。 e-&gt;结果 参数将传递给里面的RunWorkerCompleted事件 RunWorkerCompletedEventArgs
  2. sender参数是您可以使用的后台工作程序 最终为DoWorkEventArgs提升UI线程的事件 包含从调用线程传递的参数(具有的参数) 叫RunWorkerAsync(Object)
  3. 无论你需要做什么。注意用户界面 无法从DoWork线程访问的元素。通常,一个 计算完成的工作百分比并更新UI(进度 bar或类似的东西)并调用ReportProgress进行通信 UI线程。 (需要设置WorkerReportProgress属性 真)
  4. 没有任何东西无限期地运行。您可以随时拔下电源线。 说真的,它只是另一个线程,操作系统会处理它 在您的应用结束时销毁所有内容。
  5. 不确定这是什么意思,但它可能是相关的 到下一个问题
  6. 您可以使用Thread.Sleep或Thread.Join方法来释放 一个循环后的CPU时间。睡觉的确切时间应该没问题 根据你正在做的事情调整,当前的工作量 系统和处理器的原始速度
  7. 请参阅BackgroundWorkerThread

    上的MSDN文档