同步上下文和InvokeRequired

6

我一直在寻找这个问题的答案,但似乎找不到令人满意的答案。也许有人能给我指点迷津。

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

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


你最好检查一下。当你的绑定列表在工作线程上创建时,SynchronizationContext.Current将为空。否则,Send()会立即在UI线程上执行。 - Hans Passant
我将SynchronizationContext传递给列表,因为它绑定到UI。当我触发ListChanged事件时,我会检查是否有SynchronizationContext再使用它。 - Dan
2个回答

3

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


-2

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

因此,例如以下代码:

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

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


2
当然不会!首先,堆栈是一个每个线程分配的结构。所有发送操作只是发布委托,然后等待它完成。它使用互斥锁来实现这一点。您发布的循环将不会使工作线程或UI线程的堆栈增加超过1(在工作线程上发送,在UI线程上调用委托)。如果“同步上下文”足够聪明,从UI线程调用只会将一个帧推送到堆栈中。 - Gusdor
换句话说,这里没有发生递归。 - snarf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接