【问题标题】:Making thread-safe calls to windows forms controls对 Windows 窗体控件进行线程安全调用
【发布时间】:2014-03-22 17:49:36
【问题描述】:

MSDN 文章:How to: Make Thread-Safe Calls to Windows Forms Controls 说我们应该使用异步委托来进行调用。但是为什么异步委托使调用安全?

【问题讨论】:

    标签: c# .net winforms


    【解决方案1】:

    Windows 控件使用组件对象模型 (COM) 单线程单元 (STA) 模型,因为这些底层控件是单元线程的。此外,许多控件将消息泵用于许多操作。该模型表明,对每个控件的所有函数调用都必须在创建该控件的同一线程上。 Invoke(以及 BeginInvoke 和 EndInvoke)将方法调用编组到正确的线程。

    来自 Bill Wagner 的《更有效的 C#》。 Item 16. 理解 Windows 窗体和 WPF 中的跨线程调用

    【讨论】:

      【解决方案2】:

      您将调用 control.BeginInvoke() 或 control.Invoke(),该方法将负责将您的委托安全地插入 GUI 调度线程,因此稍后您的委托将在 GUI 中处理和执行线程而不是你所在的线程

      【讨论】:

        【解决方案3】:

        底线是:您不应该从创建控件的线程(UI/主线程)以外的线程更新 UI 控件。否则您可能会看到一些不可预知的行为。

        如果您需要从工作线程(主线程除外)更新 UI,则需要在更新 UI 之前切换回 UI 线程。

        文章建议使用

        • IsInvokeRequired(如果当前线程不是创建 UI 的线程,则返回 true。)和 Invoke(delegate) 在正确的/UI 线程上运行委托。当您想要在异步过程之间更新 UI 时,这很有用。例如在 UI 上更新进度。

        • BackgroundWorker 将注册的处理程序执行到其DoWork 事件异步。在工作线程上运行注册的处理程序到调用线程上的RunWorkerCompleted 事件。如果您想在异步任务完成后更新 UI,这是理想的选择。例如在 UI 上发布完成指示

        【讨论】:

          【解决方案4】:

          因为 Windows 窗体控件是这样设计的,所以它们只能从线程内部访问,这是它们的责任。如果使用得当,异步委托可以确保调用安全。

          给定问题的实际答案包含在给定 MSDN 文章的第二段 =)

          对 Windows 窗体控件的访问本质上不是线程安全的。如果您有两个或更多线程操作控件的状态,则可能会强制控件进入不一致的状态。其他与线程相关的错误是可能的,例如竞争条件和死锁。确保以线程安全的方式执行对控件的访问非常重要。

          你应该检查你是否可以立即访问控件,而不是间接(检查 InvokeRequired 属性),如果你不能,你应该异步访问它(非常简单的解释:系统将等待直到它可以安全地访问一个控件)

          【讨论】:

          • 异步委托如何避免这种情况?
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2023-03-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-03-01
          相关资源
          最近更新 更多