3

假设在实例化表单/控件/元素(通常是主线程)的线程中运行的代码不会同时修改/访问该元素,是否有可能:

  1. 获取 TextBox 的 Text 属性。

  2. 枚举一个 ListView。

  3. 订阅 Form 的 Closing 事件。(知道钩子将从实例化该表单的线程中调用)

我已经尝试了所有 3 个程序,并且该程序似乎没有抱怨它。我一直认为您必须调用任何想要远程触摸任何与 UI 相关(读取或写入)的调用。

我非常清楚为什么在修改元素时需要使用 IsInvokeRequired/Invoke 模式,但我不明白为什么访问属性/事件会导致任何问题。

4

3 回答 3

5

这绝对是可能的,但是,它可能会导致意外的行为。此外,还需要考虑其他与线程相关的错误,例如竞争条件/死锁,请参阅托管线程最佳实践

为了安全起见,我总是坚持在 UI 线程上访问 UI。

于 2012-12-20T16:01:38.310 回答
3

您在做什么来确保 UI 线程在您读取控件时不会修改控件?编组到 UI 线程的全部原因是您无需担心这种情况。特别是枚举列表框将是最容易破坏的,因为它将花费最长的时间(这为竞争条件创建了最大的窗口)。您应该为所有这 3 件事编组到 UI 线程。

于 2012-12-20T16:02:15.687 回答
2

这是不安全的。当您从另一个线程读取控件时,UI 线程可以(并且可能会)更改控件的状态。您的读取可能会使控件处于半生不熟的状态。它现在可能看起来正在工作,但迟早会失败......可能无法预测和壮观。

不,您可能不需要使用 Invoke 模式。坦率地说……这种模式通常是最糟糕的选择。通常最好让您的工作线程完成繁重的工作,然后通过队列将新数据或进度信息发送到 UI 线程,并让 UI 线程通过计时器来获取这些信息。这有几个优点。

  • 消除了昂贵的Invoke操作BeginInvoke
  • UI 线程可以决定何时以及多久使用新数据更新自己,而不是让工作线程决定这一点。
  • 您可以在工作线程上获得更多吞吐量,因为它不必等待Invoke返回。
  • 不会像BeginInvoke.
  • 它将 UI 和工作线程交互解耦。

您将需要枚举ListView并构建一个单独的数据结构,然后工作线程可以安全地访问该数据结构。如果ListView包含很多项目,请考虑与控件一起维护一个单独的集合。这样一来,您就可以在更长的时间内分散处理数据的损失,在这段时间内,它可能不会被太多人注意到。毕竟,我们不希望复制操作冻结 UI 线程,否则用户会注意到。AConcurrentBag等可能是一个不错的选择,因为它可以在工作线程读取它时由 UI 线程安全地修改。

于 2012-12-20T20:52:53.787 回答