应用程序在Visual Studio之外会冻结。从Visual Studio启动它时,它可以正常工作。

11

我有一个应用程序,其中包含线程、计时器、调用(不是BeginInvoke,因此同步)和Application.DoEvents。

由于内容过多,无法在此处发布,也不知道真正的问题所在。

我的每个方法都在try catch中。每个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() 和 invoke 中的示例。

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获取了一些信息。

编辑:2012年6月14日

!threads

                                      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.

1
你手头上遇到了死锁问题。这种问题很难诊断。 - zmbq
可能存在内存泄漏导致程序耗尽内存 C#中的内存泄漏如何检测C#应用程序中的内存泄漏? - PresleyDias
是的,我也同意zmbq的观点。从IDE中运行会使它变得非常缓慢,因此并发锁定的可能性就会降低。 - Christoph Grimmer
2
你如何使用Application.DoEvents?对我来说,这是一个警告信号。 - Chris Dunaway
我会避免使用DoEvents -- 看起来你可以很容易地使用后台线程执行该检查(检查grabber.readystate并在必要时调用grabber.navigate)。由于DoEvents引起的可重入问题与使用线程一样难以调试和正确处理。此外,请记住,锁无法防止DoEvents的可重入性,因为DoEvents调用的可重入代码可能正在运行持有锁的同一线程上。 - JMarsch
显示剩余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");

谢谢。通过线程,我找到了我主要问题的编辑部分。 - masterchris_99
你可以尝试使用BeginInvoke而不是Invoke,这样就不会等待调用返回,但我建议在Windows Forms环境中使用System.Windows.Forms.Timer。Windows Forms计时器Tick事件在GUI线程中触发,因此您不必担心同步问题。 - Jürgen Steinblock
目前我使用System.Windows.Forms.Timer和一些锁,但没有任何改进。 - masterchris_99

3

0

Invoke 是危险的,可能会以意想不到的方式导致死锁。我建议替换

this.Invoke((MethodInvoker)...

this.BeginInvoke((MethodInvoker)...

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

如果没有解决问题,您需要等待直到发生死锁,然后使用 windbg 查看死锁原因。


0

当从VS运行时,它会注入一个调试器线程,改变一些消息路由。你可能会遇到一个问题,即你的Invoke(...)在等待队列中的消息时被阻塞,但在调试器下,窗口消息以不同的顺序处理。

如果我理解正确,使用System.Windows.Forms.Timer时不需要锁,因为它使用win消息泵,所以计时器事件总是在GUI线程上处理(除非应用程序中的其他内容正在TheadPool或专用后台线程上运行代码)。

因此,除非Web浏览器控件在后台线程上触发其事件(在这种情况下,请使用BeginInvoke()将它们POST回UI线程),否则您的示例代码中没有涉及线程。一旦您让所有应用程序控制在主UI线程上运行,请删除锁(作为调试工具)。请发布有关后台处理的更多信息和任何结果。


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