问题 应用程序在Visual Studio外冻结。从Visual Studio启动时它可以工作


我慢慢地过度工作......

我有一个庞大的应用程序,包括线程,定时器,调用(不是BeginInvoke,因此它是同步的)和Application.DoEvents。

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

我的每一种方法都在尝试捕获。记录每个渔获量。

如果我从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来获取一些信息

编辑:2012年6月14日

!线程

                                      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.

10848
2018-06-05 09:31


起源

你的手上有僵局。但这些很难诊断出来。 - zmbq
可能是内存泄漏导致内存不足 内存泄漏c锐利 , in-c-sharp-application中如何检测内存泄漏? - PresleyDias
是的,会说和zmbq一样。从IDE运行它会大大减慢速度,因此不太可能发生并发锁定。 - Christoph Grimmer-Dietrich
使用grabber.InvokeRequired然后使用this.Invoke()是没有意义的。在允许表单关闭之前,始终确保线程已结束,计时器已禁用且所有Elapsed调用已耗尽。绝对不要使用Timers.Timer 10秒间隔,Winforms计时器也可以正常工作,不会给你同步的痛苦。 - Hans Passant
你如何使用Application.DoEvents?对我来说这是一面红旗。 - Chris Dunaway


答案:


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

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");

8
2018-06-05 09:41



谢谢。通过线程,我找到了主要问题的编辑部分 - masterchris_99
你可以尝试使用 BeginInvoke 而不是 Invoke 它不会等待回电话,但我会用 System.Windows.Forms.Timer,您在Windows窗体上下文中使用此代码,对吧? Windows窗体计时器Tick事件在GUI线程中触发,因此您不必担心同步。 - Jürgen Steinblock
目前我使用System.Windows.Forms.Timer和一些锁,但没有任何改进。 - masterchris_99


如果它冻结了,你很可能会陷入僵局。我发现找到死锁的最好方法之一是使用故障转储和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


3
2018-06-07 14:23





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

this.Invoke((MethodInvoker)... 

this.BeginInvoke((MethodInvoker)...

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

编辑如果没有,你将需要等到它死锁,然后使用windbg来查看你为何陷入僵局。


0
2018-06-13 17:49





从VS运行时,它将注入调试器线程,这会更改一些消息路由。你可能有问题 Invoke(...) 阻塞正在等待队列中的消息的东西,但在调试器下,win消息以不同的顺序处理。

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

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


0
2018-06-13 23:50