从一组控制台应用程序中彻底查杀控制台应用程序

jwb*_*555 6 c# wpf process

我有一个Windows窗体,使用相应的程序(它多次调用program.exe)创建多个控制台应用程序

process.start().  
Run Code Online (Sandbox Code Playgroud)

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

process.kill() 
Run Code Online (Sandbox Code Playgroud)

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

我相信我不能用

process.CloseMainWindow()
Run Code Online (Sandbox Code Playgroud)

因为应用程序没有窗口(它通过在后台运行的控制台运行).在从正在运行的进程列表中选择要杀死的进程后,我希望通过单击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 Code Online (Sandbox Code Playgroud)

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

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

有什么方法可以干净地关闭流程吗?我想当我想要杀死进程时调用一个事件可能会有效,但到目前为止我还没有能够让这个想法工作,因为我无法指定我想要关闭哪个进程.

**编辑 - 我试图提出的事件处理代码,但它无法正常工作.

主窗口中的代码

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

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;
    }

}
Run Code Online (Sandbox Code Playgroud)

正在由主窗口启动的代码

 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");
        }
    }
Run Code Online (Sandbox Code Playgroud)

Jim*_*hel 5

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

当然,这假设您已经为程序创建了一种干净利落的方式.

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

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

有关使用命名等待句柄在进程间进行通信的示例,请参阅从一个正在运行的控制台应用程序发送消息到另一个