【问题标题】:How do I wait for a BackgroundWorker to complete?如何等待 BackgroundWorker 完成?
【发布时间】:2013-03-09 02:44:06
【问题描述】:

我已经阅读了How to wait for a BackgroundWorker to cancel? 的答案,但我找不到针对我的具体问题的解决方案:

我的应用必须加载大量数据,但在大多数情况下,应用启动后不会立即需要这些数据。

为了最大限度地减少用户实际请求数据时的延迟,我使用 BackgroundWorker 加载它,它在应用启动时启动。希望当用户请求数据时,BackgroundWorker 已经完成。

但是,在某些情况下,它可能没有。在这些情况下,我想等待加载完成,然后再向用户显示任何内容。

我能想到的所有技术都有竞争条件:例如,如果我设置了AutoResetEvent,当用户请求数据时我不能使用WaitOne(),因为AutoResetEvent 可能已经发出信号;如果我添加一个布尔值 loading_complete 标志并在调用 WaitOne 之前检查它,loading_complete 可能会在 ckecing 之后设置为 true,但在 WaitOne 调用之前,它永远不会返回......

有什么想法吗?

编辑:感谢@500-InternalServerError 的解决方案;使用ManualResetEvent 效果很好。感谢其他人的建议。

【问题讨论】:

  • 如果您使用.net 4.0或以上版本,您可以使用Task
  • @HamletHakobyan 不幸的是,我正在使用适用于 Windows Phone 的 SilverLight,它没有 Task...
  • 好吧,只需在 RunWorkerCompleted 事件中启用一个按钮即可。
  • 只需在启动后台工作程序之前使用手动重置事件,然后在主线程中等待。然后后台工作人员在完成唤醒主线程时设置它。
  • Wait 在这种情况下会立即返回,这应该是你想要的。

标签: c# multithreading


【解决方案1】:

在 WorkCompleted 事件处理程序中放置 BackgroundWorker 完成后应该发生的任何事情

【讨论】:

  • BackgroundWorker 完成后不会发生任何事情,至少在我启动 BackgroundWorker 时我不知道:我只使用它之后加载的数据
  • 我认为也许狒狒的意思是BackgroundWorker应该触发那个事件,所有其他线程应该在恢复工作之前等待这个事件。
  • @didierc:我明白,但是当我进入需要数据完全加载的应用程序部分时,我无法知道事件是否已经触发。换句话说,当我到达需要等待数据的地步时,WorkCompleted 事件可能已经触发,也可能尚未触发,如果我使用布尔标志进行检查,我将遇到竞争条件。
  • @didierc 然后你需要重新考虑你是怎么做的,如果你需要完成 bgw 但不能等他说“我完成了”那么你就有架构问题。
  • @Clément 我的意思是给你,不是 diierc ;)
【解决方案2】:

后台工作人员支持 RunWorkerCompleted 事件。该事件可用于判断加载是否完成。

有两个条件

  • 用户在工作人员完成后请求数据。

为了让事情变得不那么复杂,您可以添加一个布尔成员变量,当后台工作程序开始加载数据时,该变量将设置为 false。加载数据后,将触发 runworkercompleted 事件,该事件将变量设置为 true,这将帮助您确定数据是否已加载。

  • 在工作人员完成(可以从上述布尔变量确定)并等待数据加载之前,用户已请求数据。

当用户请求数据时,可以设置一个标志/另一个布尔变量,如

WaitingForData = true;

当 RunWorkerCompleted 事件被触发时,它将检查 WaitingForData 的状态,如果为真,它将显示数据。这样,您将无需等待线程完成。

使用此方法将帮助您避免任何竞争条件或线程间通信。

【讨论】:

  • 这听起来是个好主意,但它并没有考虑到我的应用程序中有多个数据可视化页面的事实,BackgroundWorker 不会知道将数据发送到哪个.. . 不过,@500-InternalServerError 的解决方案效果很好。
  • 如果你有多个组件显示数据,你可以在多个地方消费事件。
  • 考虑到 UI 布局的成本,用数据渲染所有 UI 元素是不可行的,因为最终只会显示一个。
  • 可能我无法理解您到底想要实现什么,但我发现您的应用程序存在架构问题。这种情况一开始就不应该发生。如果您再解释一下,我可以为您的问题提供高效的解决方案。
  • 谢谢,但问题在我这边已经解决了。 @500-InternalServerError 完美运行。
【解决方案3】:

使用由BackgroundWorker 锁定的简单互斥体,并让任何其他等待完成的线程获取和释放它。一旦BackgroundWorker 完成,让它释放锁,所有其他线程应该能够继续他们的工作。

可能有一些特定的 C# 方法可以做到这一点(我认为Monitor class 可能很方便)。

更新:事实上,解决问题所需的对象是一种用作闩锁的条件变量,正如 OP 所述,ManualResetEvent 满足了这一特定需求。

【讨论】:

    【解决方案4】:

    使用布尔标志,在后台工作人员完成事件处理程序中将其设置为 true。

    当您需要检查数据是否加载时,只需检查变量即可。

    确保在尝试访问之前锁定它以避免竞争条件。

    如果数据在被请求时尚未准备好,您可以在此时向后台工作人员完成事件添加另一个事件处理程序,该事件处理需要对数据执行的操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多