首页 > 解决方案 > 如何完全停止使用 System.Diagnostic.Process.Start 启动的 .bat 文件(和子进程)

问题描述

语境

我正在使用来自 Matlab 的 .Net System.Diagnostic.Process对象运行,没有任何弹出控制台窗口,我将一些外部处理实时重定向到 matlab 控制台(或任何 matlab 进度) -gui 将来)。

要运行的程序是一个.bat文件,它本身运行一个 python 脚本 (preprocessing.py),最终在内部调用一个可执行文件 (processing.exe)。

到目前为止,一切都很好,包括 stdout/stderr 的重定向,除了尝试在 matlab 端停止执行(使用ctrl+c)时,我可以从任务管理器中看到调用Process.Kill()不会停止,python 引擎(python.exe)和也不是python脚本(processing.exe)的可执行调用。然后我的 matlab 脚本被阻止,Process.WaitForExit()直到我从任务管理器中手动终止 python.exe 或 processing.exe。

为什么在 .bat 文件上运行的初始 System.Diagnostic.Process 上的 Kill() 方法不会杀死其他子进程并使我锁定在 WaitForExit 中?...我可以强制杀死 processing.exe 但它很脏(我不应该知道任何可能启动的子进程)。

matlab代码

基本上我的 matlab 代码如下所示:

function [] = main(guicallbacks)
%[
    % Init process
    process = System.Diagnostic.Process();
    process.StartInfo.Filename = 'Processing.bat';
    process.StartInfo.CreateNoWindow = true;
    process.UseShellExecute = false;
    process.RedirectStandardOutput = true;
    process.RedirectStandardError = true;

    % Attach to process events
    l = event.listener(process, 'OutputDataReceived', @onStdOut); l.Recursive = true;
    l = event.listener(process, 'ErrorDataReceived', @onStdErr); l.Recursive = true;

    % Start process
    Start(process);
    cuo = onCleanup(@()stopProcess(process));
    process.BeginOutputReadLine();
    process.BeginErrorReadLine();

    % Wait for process
    canceled = false;
    while (~double(process.HasExited))
    
        % Check for cancellation (progress gui, etc...)
        canceled = guicallbacks.IsCancelPending();
        if (canceled), break; end

        % Wait
        pause(1.0);

    end

    % Check stop reason
    if (canceled), error('System:OperationCanceledException', 'User cancelation'); end
    if (double(process.ExitCode) ~= 0), error('Process failed (ExitCode = %i)', double(process.ExitCode)); end
%]
end
function [] = onStopProcess(process)
%[
    if (double(process.HasExited())), return; end

    process.Kill();
    process.WaitForExit();
%]
end
function [] = onStdOut(varargin)
%[
    cprintf('blue', char(varargin{2}.Data));
%]
end
function [] = onStdErr(varargin)
%[
    cprintf('red', char(varargin{2}.Data));
%]

.bat 文件

基本上,除了设置一些环境变量外,.bat要调用的文件如下所示:

python.exe -u preprocessing.py

蟒蛇脚本

python脚本以这种方式调用final processing.exe可执行文件:

subprocess.call("processsing.exe");

标签: python.netmatlabbatch-filesystem.diagnostics

解决方案


下面是 matlab 中针对@rahnema1 指出的解决方案的改编,以完全杀死进程及其子进程(递归地):

function [] = onStopProcess(process)
%[
    if (double(process.HasExited())), return; end

    killProcessTree(process.Id);
    process.WaitForExit();
%]
end

function [] = killProcessTree(processId)
%[
    % https://stackoverflow.com/a/10402906/684399
    NET.addAssembly('System.Management');
    mos = System.Management.ManagementObjectSearcher(sprintf('Select * From Win32_Process Where ParentProcessID=%i', processId));
    mos = mos.Get();
    mos = mos.GetEnumerator();
    while(mos.MoveNext())
        pd = mos.Current.Properties.Item('ProcessID');
        killProcessTree(double(pd.Value));
    end
    try
        endOfLeafProcess = System.Diagnostics.Process.GetProcessById(processId);
        endOfLeafProcess.Kill();
    catch
    end    
%]
end

推荐阅读