【问题标题】:SynchronizationContext and InvokeRequiredSynchronizationContext 和 InvokeRequired
【发布时间】:2011-03-28 22:20:46
【问题描述】:

我一直在寻找这个问题的答案,但似乎找不到满意的答案。也许这里有人可以启发我。

我有一个 BindingList<T> 的后代,它存储对 SynchronizationContext 对象的引用,以便在 UI 线程上引发其更改的事件。

现在,这个BindingList<T> 也有可能是在 UI 线程而不是后台线程上创建和使用的。如果没有像 InvokeRequired 这样的属性可供我使用,我该如何检查?在 UI 线程上调用SynchronizationContext.Send 会有什么后果?

【问题讨论】:

  • 你最好检查一下。在工作线程上创建绑定列表时,SynchronizationContext.Current 将为空。 Send() 否则立即在 UI 线程上执行。
  • 我将 SynchronizationContext 传递给列表,因为它已绑定到 UI。当我引发 ListChanged 事件时,我会在使用前检查是否有 SynchronizationContext。

标签: c# winforms multithreading invokerequired synchronizationcontext


【解决方案1】:

SynchronizationContext 上的 Send 方法将同步执行并调用绑定到SynchronizationContext 的线程上的委托。如果 SynchronizationContext 绑定到 UI 线程并且代码当前正在 UI 线程上执行,则直接调用委托,无需在线程之间编组。

【讨论】:

    【解决方案2】:

    send 方法将在 UI 线程上同步执行,这是真的。 但是,需要担心的一个可能后果是调用 Send 会增加调用堆栈。

    所以,例如下面的代码:

    for (int i = 0; i < 10000000; i++) syncContext.Send(....);
    

    将导致 StackOverflow 异常... 这就是为什么如果您已经在所需的线程上运行,避免使用同步上下文可能是明智的。 除了做一些内部簿记之外,我不知道有任何完整的方法来检查列表是在哪个线程上创建的。

    【讨论】:

    • 肯定不会!首先,堆栈是按线程分配的结构。所有 send 所做的只是发布委托,然后然后等待完成。它使用互斥锁来做到这一点。您发布的循环不会将工作线程或 UI 线程的堆栈增加超过 1(在工作线程上发送,在 UI 线程上调用委托)。如果SynchronizationContext足够聪明,从UI线程调用只会将一帧推入堆栈。
    • 也就是说这里没有递归发生。
    猜你喜欢
    • 2012-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多