【问题标题】:Application freezes outside of Visual Studio. While starting it from Visual Studio it works应用程序在 Visual Studio 之外冻结。从 Visual Studio 启动它时,它可以工作
【发布时间】:2012-06-09 07:48:07
【问题描述】:

慢慢地我过度劳累了......

我有一个带有线程、计时器、调用(不是 BeginInvoke,所以它是同步的)和 Application.DoEvents 的大型应用程序。

在这里发帖太多了,我不知道问题出在哪里。

我的每个方法都在一个 try catch 中。每一次捕获都会被记录下来。

如果我从 Visual Studio (F5) 启动我的应用程序或通过 Ants 对其进行分析,则没有问题。该应用程序从几天开始运行。 但是,一旦我通过 Windows 资源管理器启动相同的调试版本,它就会每隔几个小时冻结一次。它毫无例外地冻结。 如果我将 Visual Studio 附加到此应用程序并破坏它,它会在 Application.Run(new Form1());

上停止

我真的很困惑,不知道要修复它。

这是一个 .net 3.5 winforms 应用程序

这里好像挂了一个线程:

if (grabber.InvokeRequired)
{
    Console.WriteLine("grabber.InvokeRequired");
    this.Invoke((MethodInvoker) delegate { grabber.Navigate("http://www.google.de"); }); // <-- hang
}
else
{
    grabber.Navigate(ig.StartUrl);
}

这个 sn-p 是计时器事件的一部分

_timeout = new System.Timers.Timer(10000);
_timeout.Elapsed += new ElapsedEventHandler(OnWatchDogBark);

编辑

DoEvents() 的示例。这是在 lock() 和调用中

grabber.DocumentCompleted -= grabber_DocumentCompleted;
grabber.Navigate("http://www.google.de");

while (grabber.ReadyState != WebBrowserReadyState.Complete)
{
    timeout--;
    Application.DoEvents();
    Thread.Sleep(200);

    if (timeout < 0)
    {
        timeout = 50;
        grabber.Navigate("http://www.google.de");
    }
}

目前我使用 System.Windows.Forms.Timer 和一些锁,但没有任何改进。

好的,我用 WinDbg 来获取一些信息

编辑:14.06.2012

!线程

                                      PreEmptive   GC Alloc           Lock
       ID OSID ThreadOBJ    State     GC       Context       Domain   Count APT Exception
   0    1 37ec 007cab18      6020 Enabled  00000000:00000000 007c8510     0 STA System.ArgumentException (02762ba8)
   2    2 85b8 007d7c38      b220 Enabled  00000000:00000000 007c8510     0 MTA (Finalizer)
XXXX    3    0 06e9f548      9820 Enabled  00000000:00000000 007c8510     0 Ukn
  21    5 3464 0d6dc598   200b020 Enabled  28cb5820:28cb5fe8 007c8510     0 MTA
  22    6 62b0 0d6db9e0   200b220 Enabled  00000000:00000000 007c8510     0 MTA
  23    7 8e58 0d6db5f8    80a220 Enabled  00000000:00000000 007c8510     0 MTA (Threadpool Completion Port)
XXXX    4    0 06f62d40   1801820 Enabled  00000000:00000000 007c8510     0 Ukn (Threadpool Worker)
XXXX    f    0 132a3290   1801820 Enabled  00000000:00000000 007c8510     0 Ukn (Threadpool Worker)
XXXX   10    0 132a3678   1801820 Enabled  00000000:00000000 007c8510     0 Ukn (Threadpool Worker)
XXXX    e    0 132a26d8   1801820 Enabled  00000000:00000000 007c8510     0 Ukn (Threadpool Worker)
XXXX    9    0 0d6db210   1801820 Enabled  00000000:00000000 007c8510     0 Ukn (Threadpool Worker)

!dlk

Examining SyncBlocks...
Scanning for ReaderWriterLock instances...
Scanning for holders of ReaderWriterLock locks...
Scanning for ReaderWriterLockSlim instances...
Scanning for holders of ReaderWriterLockSlim locks...
Examining CriticalSections...
Could not find symbol ntdll!RtlCriticalSectionList.
No deadlocks detected.

【问题讨论】:

  • 您的手上出现了僵局。不过,这些都很难诊断。
  • 是的,和 zmbq 一样。从 IDE 运行它会大大降低它的速度,因此并发锁不太可能发生。
  • 使用grabber.InvokeRequired然后使用this.Invoke()是没有意义的。在允许表单关闭之前,请始终确保线程已结束、计时器已禁用并且所有 Elapsed 调用已耗尽。并且绝对不要在 10 秒的间隔内使用 Timers.Timer,W​​informs 计时器也可以正常工作,并且不会给您带来同步痛苦。
  • 如何使用 Application.DoEvents?这对我来说是一个危险信号。

标签: c# visual-studio-2010 visual-studio-2008 freeze


【解决方案1】:

当从 VS 运行时,它会注入一个调试器线程,这会改变一些消息路由。您的Invoke(...) 阻止了队列中正在等待消息的某些内容可能存在问题,但在调试器下,获胜消息的处理顺序不同。

IIUC 您不需要使用 System.Windows.Forms.Timer 锁定,因为它使用 win 消息泵,因此计时器事件始终在 GUI 线程上处理(除非您的应用程序中的其他东西正在 TheadPool 或专用后台线程)。

因此,您的示例代码中没有任何内容涉及线程,除非 Web 浏览器控件在后台线程上触发其事件(在这种情况下,使用 BeginInvoke() 将这些事件发送回 UI 线程)。一旦你在主 UI 线程上运行了所有应用程序控件,就移除锁(作为调试辅助)。请发布有关后台处理的更多信息以及迄今为止的任何结果。

【讨论】:

    【解决方案2】:

    调用很危险,很容易以意想不到的方式导致死锁,我建议更换

    this.Invoke((MethodInvoker)...

    this.BeginInvoke((MethodInvoker)...

    这不会阻止调用者并且可能会解决问题。

    如果不是,请编辑,您需要等到它死锁,然后使用 windbg 查看您死锁的原因。

    【讨论】:

      【解决方案3】:

      如果它冻结,您可能会看到死锁。我发现找到死锁的最佳方法之一是使用故障转储和 sosex。

      这是一篇关于使用这种技术的好文章(它是 asp.net,但同样适用):http://blogs.msdn.com/b/tess/archive/2010/04/27/debugging-a-classic-readerwriterlock-deadlock-with-sosex-dll.aspx

      让应用程序运行直到它冻结,然后进行挂起转储:http://blogs.msdn.com/b/tess/archive/2006/10/16/net-hang-debugging-walkthrough.aspx

      【讨论】:

        【解决方案4】:

        可能是后台线程中的死锁。 尝试查看可能阻止您的应用的其他线程。

        Toolbar -> Debug -> Windows -> Threads
        

        http://msdn.microsoft.com/en-us/library/w15yf86f.aspx

        应该有多个线程,如果您双击一个线程,您会看到它正在停止您的应用程序的行。

        如果你的代码中有这一行:

        Control.CheckForIllegalCrossThreadCalls = false;
        

        再次将其设置为 true。死锁的一个可能原因是后台线程访问控件。

        而不是从背景线程中编写。

        button1.Text = "hello"
        

        写这个。

        this.Invoke(() => button1.Text = "hello");
        

        【讨论】:

        • 谢谢。通过线程我找到了我的主要问题的编辑部分
        • 您可以尝试使用BeginInvoke 而不是Invoke,它不会等待调用返回,但我会使用System.Windows.Forms.Timer,您在Windows 窗体上下文中使用此代码, 正确的? Windows Forms Timer Tick 事件在 GUI 线程中触发,因此您不必担心同步问题。
        • 目前我使用 System.Windows.Forms.Timer 和一些锁但没有任何改进。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多