[英]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). 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 将来)。
The program to run is a .bat
file, that itself runs a python script (preprocessing.py) that finally internally calls an executable (processing.exe).要运行的程序是一个
.bat
文件,它本身运行一个 python 脚本 (preprocessing.py),最终在内部调用一个可执行文件 (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).到目前为止,一切正常,包括 stdout/stderr 的重定向,除了尝试在 matlab 端(使用
ctrl+c
)停止执行时,我可以从任务管理器中看到对Process.Kill()
的调用不会停止,也不会停止python 引擎 (python.exe) 和 python 脚本 (processing.exe) 的可执行调用。 My matlab script is then blocked in Process.WaitForExit()
until I manually kill python.exe or processing.exe from the task manager.然后,我的 matlab 脚本在
Process.WaitForExit()
中被阻止,直到我从任务管理器中手动杀死 python.exe 或 processing.exe。
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?为什么初始 System.Diagnostic.Process 上的 Kill() 方法运行 on.bat 文件不会杀死其他子进程并使我锁定在 WaitForExit 中? ... I can force-kill processing.exe but it's dirty (I'm not supposed to know anything about possible child processes started).
...我可以强制杀死 processing.exe 但它很脏(我不应该知道任何可能启动的子进程)。
The matlab code matlab代码
Basically my matlab code looks like this:基本上我的 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));
%]
The.bat file .bat 文件
Basically, execept for setting a few environment variables the .bat
file to call looks like this:基本上,除了设置一些环境变量之外,要调用的
.bat
文件如下所示:
python.exe -u preprocessing.py
The python script python 脚本
The python script call final processing.exe executable this way: python 脚本调用 final processing.exe 可执行文件如下:
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):下面是 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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.