【问题标题】:How do I know if Process.WaitForExit() expired due to main application close我如何知道 Process.WaitForExit() 是否因主应用程序关闭而过期
【发布时间】:2023-03-26 19:56:01
【问题描述】:

我有一个 C# 控制台程序“A”来监视另一个应用程序“B”的 4 个实例。

控制台程序为每个“B”实例创建一个线程,每个线程使用Process.Start() 启动“B”。然后线程使用Process.WaitForExit(3000);等待3秒

在那之后,它会检查应用程序“B”的实例是否正在运行。如果没问题,再等。否则,如果它不起作用或已经完成,它会重新启动它。当用户关闭控制台程序时,所有应用程序都应该结束。

但是,当应用程序“A”使用控制台的关闭按钮关闭时,WaitForExit() 在所有线程中恢复,并导致应用程序“B”重新启动。

我想检测WaitForExit() 是否由于受监控应用程序“B”的故障或主应用程序“A”正在退出而恢复。在这种情况下,应用程序“B”不会重新启动,问题将得到解决。

我尝试使用以下方法捕获结束事件:

[DllImport("Kernel32")]
public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add);

问题在于 WaitForExit() 在调用处理程序例程之前已恢复。

更多信息:

Main() 方法启动线程:

for(int i = 0; i < 4; i++)
{
       Thread t = new Thread(() => MonitorizeApp(arguments));
       t.IsBackground = true;
       t.Start();
}

我还尝试将线程从后台更改为前台,这样主应用程序就不会退出,但结果是一样的。

每个线程启动并监控第二个应用程序的一个实例:

MonitorizeApp(string arguments)
{
    LaunchProcess(arguments);
    while(!_closing)
    {
        appProcess.WaitForExit(3000);

        if (!_closing)
        {
            if ((appProcess != null) && (!appProcess.HasExited))
                DoSomeMonitoring();
            else
            {
                Console.WriteLine("WARNING: The application finished");
                Thread.Sleep(500);
                if (!_closing)
                {
                    Console.WriteLine("Re-launch");
                    LaunchProcess(arguments);
                    inicial = true;
                }
            }
        }
    }

    Console.WriteLine("\nClosing...\n");
    if(appProcess != null)
    {
        if(!appProcess.HasExited)
            appProcess.Kill();

        appProcess.Dispose();
    }
}

_closure 是在控制台关闭时从主线程设置的变量。 我使用 SetConsoleCtrlHandler 做到了这一点:

[DllImport("Kernel32")]
public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add);

public delegate bool HandlerRoutine(CtrlTypes CtrlType);

private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
{
    MonitoredApp.closing = true;
    Thread.Sleep(1000);
    closing = true;
    Environment.Exit(-1);
    return true;
}

【问题讨论】:

  • WaitForExit 将返回一个布尔值,指示进程是否已退出或超时已过。也许这就是你所追求的?

标签: c# multithreading console waitforexit


【解决方案1】:

我怀疑您唯一的选择是让主程序的退出例程检查是否有任何子进程正在运行,如果是,则终止它们。我有点惊讶你的 500 毫秒睡眠,然后是 _closing 检查没有抓住这个。虽然,查看您的代码示例,我没有看到设置了 _closing 标志(除非 _closingMonitoredApp.closing 的支持字段)。

您可以考虑将 _closing 布尔值更改为主程序设置的 ManualResetEvent。编译器很可能正在优化对_closing 的检查。您还可以将_closing 标记为volatile,这可能会改变行为。请记住,这些事情都是异步发生的,所以您必须担心竞争条件。

即便如此,您仍可能会遇到问题,您必须确保主应用程序在退出之前关闭所有现有子进程。您根本无法保证操作系统将按什么顺序关闭。

您可以通过禁用关闭按钮来避免此问题。有关示例,请参阅我的博客条目 http://blog.mischel.com/2008/07/14/going-too-far-back/。如果删除关闭菜单项,单击 X 不会关闭窗口。

当然,您的用户必须在您的窗口中键入退出命令。如果用户从任务管理器或其他类似应用程序关闭窗口,您可能仍然会遇到问题。

【讨论】:

  • 你说得对,MonitoredApp.closing 改变了 _closing 属性。我已将其更改为 volatile,但结果是一样的。您提到的 500 毫秒延迟最初并不存在。我稍后放了它,它避免重新启动应用程序,但它会导致我不太了解的 CallbackOnCollectedDelegate 异常。
猜你喜欢
  • 1970-01-01
  • 2014-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多