简体   繁体   中英

How to fully stop a .bat file (and child processes) started with System.Diagnostic.Process.Start

Context

I'm using a.Net System.Diagnostic.Process object from Matlab to run, without any popping-up console window, some external processing for which I redirect, in real time, stdout/stderr to the matlab console (or any matlab progress-gui in the future).

The program to run is a .bat file, that itself runs a python script (preprocessing.py) that finally internally calls an executable (processing.exe).

So far everything works great including redirection of stdout/stderr, except that when trying to stop execution on matlab side (with ctrl+c ), I can see from the task manager that the call to Process.Kill() does not stop nor the python engine (python.exe) and nor the executable call by the python script (processing.exe). My matlab script is then blocked in Process.WaitForExit() until I manually kill python.exe or processing.exe from the task manager.

Why the Kill() method on the initial System.Diagnostic.Process ran on.bat file does not kill the other child processes and makes me locked in WaitForExit? ... I can force-kill processing.exe but it's dirty (I'm not supposed to know anything about possible child processes started).

The matlab code

Basically my matlab code looks like this:

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));
%]

The.bat file

Basically, execept for setting a few environment variables the .bat file to call looks like this:

python.exe -u preprocessing.py

The python script

The python script call final processing.exe executable this way:

subprocess.call("processsing.exe");

Here below is adaptation in matlab for the solution pointed out by @rahnema1 to fully kill the process and its children (recursively):

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM