windows窗体中多线程和后台工作线程的几个问题

Some questions on Multithreading and Background worker threads in windows form

本文关键字:工作 线程 几个问题 后台 窗体 多线程 windows      更新时间:2023-10-16

我在使用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->Result?
  • 传入backgroundWorker1_DoWork函数的参数是什么?
  • 形参safe_cast(e->Argument)的目的是什么?
  • 我应该在我的CPUHungryFunction()做什么?
  • 如果我的CPUHungryFunction()有一个无限循环的while循环怎么办?
  • 我是否可以控制我的工作线程的处理器时间?
  • 能否更具体地控制在设定周期内循环的次数?当我只需要每秒循环30次时,我不想让cpu每秒循环1000次。*是否有必要控制GUI的更新速度?

将后台工作线程使我的多线程生活更容易吗?

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

为什么我需要e->Result?

将您所做的工作的结果传递回UI线程。您可以在RunWorkerCompleted事件处理程序e->Result属性中获得该值。然后用结果更新UI。

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

告诉工作线程该做什么,它是可选的。其他方面与传递参数给任何方法相同,只是更尴尬,因为你不能选择参数。你通常会从你的UI传递某种值,例如,如果你需要传递多个值,使用一个小的helper类。总是倾向于在工作线程中获取UI值,那是非常麻烦的。

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

当然是刻录CPU周期。或者通常做一些需要很长时间的事情,比如数据库查询。这不会消耗CPU周期,但需要太长时间才能允许UI线程在等待结果时死亡。粗略地说,当你需要做一些超过一秒钟的事情时,你应该在一个工作线程上执行它,而不是在UI线程上。

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

那么你的工人永远不会完成,也永远不会产生结果。这可能有用,但并不常见。你通常不会使用BGW,只是一个常规的线程,它的IsBackground属性设置为true。

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

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

能否更具体地控制在设定周期内循环的次数?当我只需要每秒循环30次时,我不想每秒循环1000次来耗尽cpu。

和上面一样,你必须睡觉。执行循环30次,然后休眠一秒钟。

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

是的,这很重要。ReportProgress()可以是一个消防水带,每秒生成数千个UI更新。当UI线程无法跟上这个速度时,你很容易遇到问题。您将注意到,UI线程不再执行其常规任务,如绘制UI和响应输入。因为它必须不断处理另一个调用请求以运行ProgressChanged事件处理程序。副作用是UI看起来冻结,你已经得到了你试图用worker解决的确切问题。它实际上并没有冻结,它只是看起来那样,它仍然在运行事件处理程序。但是你的用户不会看到区别。

要记住的一件事是ReportProgress()只需要保持人眼满意。它不能看到每秒发生超过20次的更新。除此之外,它就变成了难以辨认的模糊。所以不要把时间浪费在无用的UI更新上。你也会自动避免消防水管的问题。调整更新速率是你必须编程的事情,它不是内置在BGW中。

我会一个问题一个问题地回答你

  1. DoWork是一个void方法(并且需要如此)。DoWork也执行了在与调用线程不同的线程中,所以你需要返回一些东西给调用线程的方法。e ->结果参数将传递给内部的RunWorkerCompleted事件RunWorkerCompletedEventArgs
  2. sender参数是你可以使用的后台工作者本身为UI线程,DoWorkEventArgs最终引发事件包含从调用线程传递的参数(具有call RunWorkerAsync(Object))
  3. 无论你需要做什么。注意用户界面不能从DoWork线程访问的元素。通常,一个计算完成工作的百分比并更新UI(进度)bar或类似的东西)并调用ReportProgress进行通信UI线程。(需要有WorkerReportProgress属性设置为真的)
  4. 没有无限期运行。你可以随时拔掉电源线。说真的,它只是另一个线程,操作系统会处理它当你的应用程序结束时,会破坏所有的东西。
  5. 不知道你是什么意思,但这可能是相关的到下一个问题
  6. 你可以使用线程。睡眠或线程。方法来释放一个循环后的CPU时间。睡觉的确切时间应该没问题根据您正在做的事情,当前的工作负载进行调整系统和处理器的原始速度

请参考MSDN文档中的BackgroundWorker和Thread类