我遇到了在使用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 );
}
然而,有一些事情我需要直截了当地弄明白
答案 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)
我会尽力回答你的问题
DoWork
也会执行
在与调用者不同的线程中,所以你需要有一个
将某些东西返回给调用线程的方法。 e-&gt;结果
参数将传递给里面的RunWorkerCompleted
事件
RunWorkerCompletedEventArgs
DoWorkEventArgs
提升UI线程的事件
包含从调用线程传递的参数(具有的参数)
叫RunWorkerAsync(Object)
)WorkerReportProgress
属性
真)