【发布时间】:2010-03-22 13:05:21
【问题描述】:
我们在工作中遇到了一个严重的问题。我们发现,在客户端运行的站点被锁定/解锁后,客户端被阻止。没有重绘。所以 UI 线程被某些东西阻塞了。使用 windbg 查看 UI 线程(线程 0)的调用堆栈,我们看到引发了 UserPreferenceChanged 事件。它通过 WindowsFormsSynchronizationContext 使用它的 controlToSend 字段编组到 UI。它被对编组控制的调用阻止。调用的方法是 MarshaledInvoke 它构建了一个
ThreadMethodEntry entry = new ThreadMethodEntry(caller, method, args, synchronous, executionContext);
这个条目应该会变魔术。该调用是同步调用,因此(仍在 Control 类的 MarshaledInvoke 中)等待调用:
if (!entry.IsCompleted)
{
this.WaitForWaitHandle(entry.AsyncWaitHandle);
}
我可以在堆栈上看到的最后一件事是在前面提到的 AsyncWaitHandle 上调用的 WaitOne。 这很烦人,因为只有运行时的调用堆栈而不是调用我们的方法之一,我们无法真正指出代码中的错误。 我可能错了,但我猜封送控制不是“封送”到 ui 线程。但是另一个......我真的不知道是哪一个,因为其他线程正在被我们使用并且被阻止......也许这就是问题所在。但是其他线程都没有运行消息循环。这很烦人。 过去,我们在将控件编组到正确的 ui 线程时遇到了一些问题。那是因为构造的第一个表单是启动表单。这不是主要形式。我们曾经使用主窗体来编组对 ui 线程的调用。但有时,一些调用会转到非 ui 线程,一些网格会中断,上面有一个大的红色 X。我通过创建一个特定的类来解决这个问题:
public class WindowsFormsSynchronizer
{
private static readonly WindowsFormsSynchronizationContext = new WindowsFormsSynchronizationContext();
//Methods are following that would build the same interface of the synchronization context.
}
这个类被构建为第一种形式的第一个对象。
我们注意到了一些其他奇怪的事情。查看堆有 7 个 WindowsFormsSynchronizationContext 对象。其中 6 个具有相同的 controlToSend 实例,而另一个具有一些不同的 controlToSend 实例。最后一个是应该编组对 UI 的调用的那个。
我没有任何其他想法...也许你们中的一些人有同样的问题?
【问题讨论】:
标签: .net windows winforms user-interface