【问题标题】:Cleanly killing a console application from within a group of console applications从一组控制台应用程序中干净地杀死一个控制台应用程序
【发布时间】:2011-12-24 00:13:40
【问题描述】:

我有一个 Windows 窗体,它使用

创建同一程序的多个控制台应用程序(它调用 program.exe 任意次数)
process.start().  

我正在寻找一种方法来识别应用程序的特定运行并彻底终止它(即彻底关闭 program.exe 的第 5 个进程,但让所有其他进程保持运行)。我能够通过进程启动时提供的 ID 来识别 program.exe 的每个不同进程,但除了调用之外,我无法以任何方式关闭应用程序

process.kill() 

它不执行应用程序的干净关闭。

我相信我不能使用

process.CloseMainWindow()

因为应用程序没有窗口(它通过在后台运行的控制台运行)。在我从正在运行的进程列表中选择要终止的进程后,我希望通过单击 GUI 中的按钮终止这些进程。

我需要这个的原因是因为我需要在每个进程关闭之前关闭所有线程和未完成的方面。

我对每个新进程的定义如下,

Process process = new Process();
process.StartInfo = info;

ExecutionDetails details = new ExecutionDetails(run_id, process, info, session_type, strategy_type, name, ExecutionViewModel);

lock (_runs)
_runs.Add(run_id, details); // will throw on Add if duplicate id, prevent duplicate
ExecutionViewModel.NewRun(details); // add to the view model

process.Start();

其中 run_id 是标识每个进程的 GUID。

在一个单独的类中,我有通过进程执行的代码,该进程仅通过启动程序的命令提示符引用(即调用程序、提供配置变量等)。

有什么方法可以干净地关闭进程吗?我在想,当我想终止进程时调用一个事件可能会起作用,但到目前为止,我无法让这个想法起作用,因为我无法指定我想要关闭哪个进程。

** 编辑 - 我试图隐含的事件处理代码,但它不起作用。

主窗口中的代码

 public void KillOne() {
     foreach (var details in _runs.Values) {
         if(details.IsSelected) {
             StrategyStateManager.SessionClosed(this, details.RunId);
                } } }

StrategyStateManager 中的代码(用于保存要在程序中使用的变量和事件的中间类)

public delegate void StrategyCloseEventHandler(object sender, StrategyCloseEventArgs e);

    public static void SessionClosed(object sender, Guid id)
    {
        if(CloseSession != null)
            CloseSession(sender, new StrategyCloseEventArgs(id));
    }


public class StrategyCloseEventArgs : EventArgs
{

    private readonly Guid id;

    public StrategyCloseEventArgs(Guid run_id)
    {
        id = run_id;
    }

    public Guid GetRunID()
    {
        return id;
    }

}

正在由主窗口启动的进程中的代码

 StrategyStateManager.CloseSession += (closeStrategy);

 void closeStrategy(object sender, StrategyCloseEventArgs e)
    {
        if (e.GetRunID() == run_id)
        {
            strategy.cleanupForShutdown();
            DBSaverSimple.shutdownAll();
            logger.Warn("Simulation run stopped by user");
        }
    }

【问题讨论】:

    标签: c# wpf process


    【解决方案1】:

    立即想到的可能性是使用包含关闭消息和您要关闭的进程ID的广播数据报。每个控制台进程都在一个公共端口上侦听广播数据报。当程序接收到数据报时,它会解析数据,将传递的进程 id 与自己的进程 id 进行比较,如果它们匹配,则程序启动干净的关闭。

    当然,这假设您已经为程序创建了一种完全关闭自身的方法。

    当然,不能保证接收到广播数据报,但我的经验是它们在单个系统上是可靠的。如果遇到问题,可以让主程序发送数据报,等待一段时间看看程序是否已经关闭,如果没有,则再次发送数据报。

    另一种可能性是为您启动的每个进程创建一个名为EventWaitHandle,并将该事件的名称传递给命令行上的控制台应用程序。然后控制台程序可以有一个线程在该事件上执行WaitOne。设置事件后,程序将启动干净关闭。这比广播数据报更可靠。当然,它为每个进程使用另一个句柄,但除非您有数千个进程,否则这不会成为问题。

    有关使用命名等待句柄在进程之间进行通信的示例,请参阅 Send message from one running console app to another

    【讨论】:

    • 我实施了您建议的 EventWaitHandle Idea,效果很好。谢谢
    • 投反对票?提供评论以说明拒绝投票的原因是惯例。
    【解决方案2】:

    听起来好像您将在由子进程运行的单独代码中具有明确的状态,此时您希望该进程终止。为什么不在该代码路径的末尾调用Process.GetCurrentProcess().Kill(); 甚至Process.GetCurrentProcess().Close();

    这样,当它完成执行时,它会关闭/杀死自己,而其余进程将继续按照它们认为合适的方式运行(直到它们也到达它们的终止点)?

    【讨论】:

    • 当我希望代码终止时,我没有明确的时间。终止由 GUI 中的按钮单击决定。如果我使用 Process.Kill() 它将终止程序并且不执行干净的关闭并且 Process.Close() 实际上不会终止进程它只是为了释放进程的“本地”视图和相关资源。跨度>
    • 你真的试过process.CloseMainWindow()吗?如果这是来自按钮按下,您肯定有一个主窗口。您也可以尝试System.Exit() 关闭应用程序。如果在子流程中调用我相信它会给你你想要的。
    • 终止来自 GUI,但实际进程没有命令提示符中定义的用于启动进程的窗口。由于这个 Process.CloseMainWindow() 对进程没有任何作用。 System.Exit() 可以关闭它,但我需要一种能够在特定进程中调用它的方法,因为多个进程将同时运行,因此需要一个事件或其他通知来调用 System.Exit (),由于多进程情况,到目前为止我一直无法暗示。
    • 我想我的问题是,您为什么要以这种方式构建您的应用程序。为什么不简单地使用线程而不是微观管理多个进程?
    • 既然我使用的是进程类,我本质上不是使用线程吗?我还尝试创建一个可以在我的主程序中调用的事件,该事件将触发子进程中的关闭事件,但子进程中的事件永远不会被触发,因为即使它们是在子进程中创建的,也不会创建任何处理程序过程。关于为什么会发生这种情况的任何想法?我已经编辑了原始问题以显示我的事件代码
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-22
    • 1970-01-01
    • 2010-11-04
    • 1970-01-01
    相关资源
    最近更新 更多