11

慢慢地,我劳累了……

我有一个带有线程、计时器、调用(不是 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);
}

此片段是计时器事件的一部分

_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.
4

4 回答 4

8

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

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");
于 2012-06-05T09:41:31.060 回答
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

于 2012-06-07T14:23:56.293 回答
0

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

this.Invoke((MethodInvoker)...

this.BeginInvoke((MethodInvoker)...

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

编辑如果不是,您将需要等到它死锁,然后使用 windbg 来查看您为什么会死锁。

于 2012-06-13T17:49:46.183 回答
0

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

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

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

于 2012-06-13T23:50:32.833 回答