Windows在站锁定后形成应用程序块

时间:2010-03-22 13:05:21

标签: .net windows winforms user-interface

我们在工作中遇到了严重的问题。我们发现在客户端运行的工作站被锁定/解锁后,客户端被阻止。没有重画。所以UI线程被某些东西阻止了。使用windbg查看UI线程(线程0)的callstack,我们看到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。 这非常烦人,因为只有运行时的callstack而不是我们调用的方法之一,我们无法真正指出代码中的错误。 我可能错了,但我猜测编组控制不是“编组”到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的调用的那个。

我没有任何其他想法...也许你们中的一些人有同样的问题?

3 个答案:

答案 0 :(得分:1)

是的,当程序违反Windows线程规则时,SystemEvents类(SessionSwitch)生成的事件很容易导致死锁。我不清楚你的情况究竟是怎么发生的,但是听起来你已经和线程问题争论了一段时间了。

.NET 2.0为此提供了内置诊断功能。一定要利用它,它只适用于调试器。确保没有将Control.CheckForIllegalCrossThreadCalls设置为false。

答案 1 :(得分:0)

虽然这可能无法专门解决您的问题,但可以查看其他线程的调用堆栈(假设您在Visual Studio中进行调试)。有一个名为“Threads”的调试窗口(在默认菜单配置中,Debug-> Debug Windows-> Threads)。有了这个可见,您可以双击任何线程切换到它。这将加载该线程的调用堆栈,并希望希望为您提供有关正在发生的事情的更多信息。

答案 2 :(得分:0)

昨天我们确实杀死了怪物。我最初的预感是,应用程序启动表单给出了错误的行为,这是一种启动形式,后来切换为真正的主要形式。问题是2-4个月前,闪屏被慢慢消失了。这是使用计时器完成的。但是启动画面用于登录并构建一些缓存并加载一些用户首选项。其中一些操作涉及构建一些控件。为了使闪屏消失,透明度会不时变为较低的值。这是在UI线程上处理的,其他耗时的调用被发送到ThreadPool。这涉及在其他线程上创建控件。由于某种原因,其中一些控件被用于封送回UI线程。无论如何通过将这些调用重新编组到UI线程来修复它。