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

问题描述 投票:0回答:5

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

我有一个巨大的应用程序,带有线程、计时器、调用(不是 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 来获取一些信息

编辑: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.
c# visual-studio-2010 visual-studio-2008 freeze
5个回答
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");

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


0
投票

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

this.Invoke((MethodInvoker)...

this.BeginInvoke((MethodInvoker)...

这不会阻止呼叫者,并且可能会解决问题。

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


0
投票

从 VS 运行时,它将注入一个调试器线程,这会更改一些消息路由。您的

Invoke(...)
可能会阻塞正在等待队列中消息的内容,但在调试器下,获胜消息会以不同的顺序处理。

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

因此,示例代码中没有任何内容涉及线程,除非 Web 浏览器控件在后台线程上触发其事件(在这种情况下,使用

BeginInvoke()
将这些事件发布回 UI 线程)。当所有应用程序控件在主 UI 线程上运行后,请删除锁(作为调试辅助)。请发布有关后台处理和迄今为止的任何结果的更多信息。


0
投票

我最近在所有最新内容上的 .NET 8 表单应用程序中遇到了非常类似的问题。当由 Visual Studio(调试器或发布版本)启动时没有问题。当在 Visual Studio 外部运行时,它不会挂起的唯一方法是处理 UI 事件的速率非常慢。单击复选框,确定。移动滑块,挂起。

  1. 创建挂起的应用程序的调试版本
  2. 在 Visual Studio 之外启动它
  3. VS 运行时,将调试器附加到正在运行的进程
  4. 重现悬挂条件并
  5. 从 Visual Studio 调试器暂停应用程序
  6. 打开诊断工具(如果尚未打开)
  7. 单击并行堆栈选项卡
  8. 即使您已经在调试器中运行另一个应用程序,也可以查看线程和异步堆栈,直到找到调试器所附加的进程中的线程和异步堆栈。
  9. 查看每一个,直到找到挂着的那一行

对我来说,这是某人糟糕的调试留下的 Console.WriteLine 调用。我很久以前就学会了,尽可能避免使用 Console.WriteLine 进行调试。该行是几乎所有 UI 事件处理程序都会调用的通用方法。这可能不是每个人的问题,我的回答更多的是关于 VS 2022 上使用的上述配方,以便快速找到问题的核心。干杯。

© www.soinside.com 2019 - 2024. All rights reserved.