0

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

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

在那之后,它会检查应用程序“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;
}
4

1 回答 1

1

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

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

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

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

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

于 2015-02-16T22:29:25.547 回答