检测应用程序停止响应,终止并重新启动它。

8

我正在开发一款高性能应用程序,由于过载,主进程似乎会停止响应并崩溃 - 时不时地 - (我会收到关闭应用程序对话框,因此应用程序从根本上来说并没有退出,只是冻结了,这很烦人)。

我希望找到一种干净的方式来编程检测应用程序何时被冻结,以便我可以使用BAT(或其他工具)自动终止进程并重新启动。

当然,在审计应用程序的同时,这只是一个临时解决方案,但在此期间非常方便。

TieBreaker : 顺便问一下,有没有办法覆盖Windows的异常屏幕,只是退出应用程序?这通常是最烦人的功能之一。

EDIT:
拜托:这个应用程序确实会冻结,尽管每个任务都在后台工作和线程中运行!我已经在评论中指出了这一点。请相信我不是那么傻。仅仅因为你的应用程序运行在后台工作中,并不意味着它永远不会冻结!正如我所说,我只需要一个服务器上的解决方法。请不要教我如何设计我的应用程序,我已经在努力工作并且知道该做什么。感谢您。


1
为什么不使用后台线程呢?听起来像是一个奇怪的解决方案。你的应用程序在做什么导致它被冻结了? - Oskar Kjellin
2
临时解决方案有一个讨厌的习惯,就是变成永久性的补救措施 :-) - paxdiablo
你能否发布一段代码示例,让我们知道你认为或者已经确定哪里出了问题吗? - MethodMan
什么是Winform/WPF/Silverlight技术? - ΩmegaMan
定期向应用程序发送Windows消息。如果没有收到回复,请将其视为死亡 - 这基本上是Windows确定是否弹出“关闭应用程序”框的方式。 - Harry Johnston
显示剩余4条评论
3个回答

16

如果没有其他人说出来,我会说 :) 创建一个单独的表单应用程序,它可以执行以下操作-

Process[] prs = Process.GetProcesses();

foreach (Process pr in prs)
{
    if (!pr.Responding) 
    {
        try
        {
            pr.Kill();
        }
        catch { }
    }
}

//then to restart-
var process = new Process
{
    StartInfo = new ProcessStartInfo
    {
        FileName = @"C:\yourapp.exe"
    }
};
process.Start();

显然过于简化。


简单而优雅。不,不是优雅,而是有效 - 这就是我们需要的。 - CLS

2

我们通过在服务中使用主服务exe仅作为启动子线程的壳来处理此问题。

然后,子线程负责在能够记录上次“看到”它们的日期/时间时向父级线程报告。

定期间隔,服务应用程序会检查子进程列表,如果一个子进程在预定的一段时间内(即2分钟)没有被看到,但没有报告它已关闭,则父进程将首先尝试加入该线程并优雅地关闭它(通常失败),然后如果这样做不起作用,则终止该线程。

我们多年来成功地使用了这种方法,当我们运行的OCR服务由于OCR软件中的错误而经常挂起时,我们开始使用这种方法。


那很聪明。我没有指定这个,但这正是我的应用程序现在的做法。但我仍然希望跟踪应用程序的完全冻结(即“真正”和“直接”检测它以某种方式离开了控制)。但我不知道这是否可能。 - Mehdi LAMRANI
杀死一个线程可能会导致各种问题,包括挂起应用程序,例如因为被杀死的线程持有堆锁。 (我想知道这是否是楼主最初遇到的问题?!) - Harry Johnston

1
将所有的CPU密集型任务从GUI中移出,并调用回GUI来报告任何状态。
主应用程序不应该冻结。我编写了一个应用程序,生成了500多个线程(同时),并在它们异步处理多个数据库调用时进行管理(.net 2)。我认为您需要系统地将所有进程移动到线程安全的情况下,并删除任何直接的GUI调用。
补充说明:我如何运行500多个线程:
智能锁的使用从一开始就应用于所有共享数据位置。请参阅我的博客文章

C# .Net中的智能资源锁定以实现线程安全代码
使用ThreadPool,匿名委托和锁的C#多线程编程

创建了一个指定具有数据和错误状态作为属性的操作行为接口。 创建了一个基类(用于第4步和第5步的类),该基类生成、启动和清理线程操作。没有业务逻辑,只是在一个位置处理线程的方法。
根据第2步中的接口创建了一个类,并且还继承自第3步。通过接口,该类需要获取数据并放置数据(通过本地化锁实现线程安全),并报告其状态。如果没有可以进行的工作,该类还设计为通过thread.Sleep(0)而不是忙等待来放弃线程循环。
创建了一个管理类(在自己的线程上运行并派生自第3步)。它启动了1-N个第4步的类来执行工作。这些实例中的每一个都被放置到一个工作列表中。
管理类简单地浏览工作列表,寻找已完成工作的实例,如果工作已完成,则将实例移动到已完成工作列表中。管理类还记录状态(通过锁实现线程安全),并公开属性(以及子实例报告的任何错误)。在每次运行后,管理类放弃线程循环,并在再次启动之前休眠250毫秒。
GUI线程具有处理从管理类获取特定状态的工作计时器。它们会从管理类的属性中提取数据,并回调GUI以定位一个控件(gridview),该控件报告所有状态和错误。
通过这样做,我能够实现单独的线程执行特定的工作,如果进程遇到问题,它会报告成功或失败。这些消息会上报给管理器,然后上报给计时器,最终上报给GUI。GUI除了启动管理器和计时器之外不处理任何业务逻辑。

我知道这并不能立即解决你的问题,我感同身受。但在你能够将业务逻辑与 GUI 分离,并在线程(后台工作者)中处理错误情况并将其传递到 GUI 之前,你仍然会对当前代码感到沮丧。

如果某些东西被锁定,那就意味着业务逻辑与 GUI 操作过于紧密耦合,必须在你从 GUI 中获得所需性能之前进行分离。

希望有所帮助。


1
你是如何让主线程知道它们的状态的?即使有很多线程每隔一段时间报告,仍然会导致一些工作在GUI线程中完成。 - Eddie Paz
@Eddie Paz:谢谢,至少我感觉被理解了。 - Mehdi LAMRANI
@MikaJacobi 你有工作要做,这是我所做的,但也许只需要做一些智能线程资源锁定就可以帮助解决问题?希望对你有帮助。(请参见我如何完成它以及链接)祝好运。 - ΩmegaMan
@OmegaMan。好的。非常感谢您花时间写了一份详细和有建设性的答案 :) 我正在审核我的应用程序。它非常复杂,因为我在许多层面上有嵌套线程,并且我有数百个线程(它是高性能的股票市场监听器)。问题是,在原型上一切都很好,但在预生产环境中,有时线程会失控。而且很难说出为什么。有时会出现空异常、不同步的工作人员和其他奇怪的行为。我甚至放弃了 GUI,改用纯文本界面。在审核过程中,我将会查看您的列表。 - Mehdi LAMRANI
@OmegaMan:但我需要先暂时解决这个问题。我必须交付,而短期内没有其他选择。再次感谢。 - Mehdi LAMRANI
@MikaJacobi 我完全理解你需要尽快完成某项任务的心情。我看到你在巴黎。在90年代,我曾有机会在巴黎拉德芳斯的Cegetel工作。那是我生命中最好的合同之一。祝你的代码顺利,你一定能让它正常运行。 - ΩmegaMan

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