如何完全停止以 System.Diagnostic.Process.Start 开头的 .bat 文件(和子进程)
How to fully stop a .bat file (and child processes) started with System.Diagnostic.Process.Start
上下文
我正在使用从 Matlab 到 运行 的 .Net System.Diagnostic.Process 对象,没有任何弹出式控制台 window,我为之重定向的一些外部处理,实时, stdout/stderr 到 matlab 控制台(或将来的任何 matlab progress-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文件
基本上,用于设置一些环境变量的 execept .bat
要调用的文件如下所示:
python.exe -u preprocessing.py
python脚本
python 脚本以这种方式调用最终 processing.exe 可执行文件:
subprocess.call("processsing.exe");
下面是在 matlab 中针对 solution 指出的改编
@rahnema1 完全终止进程及其子进程(递归):
function [] = onStopProcess(process)
%[
if (double(process.HasExited())), return; end
killProcessTree(process.Id);
process.WaitForExit();
%]
end
function [] = killProcessTree(processId)
%[
%
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
上下文
我正在使用从 Matlab 到 运行 的 .Net System.Diagnostic.Process 对象,没有任何弹出式控制台 window,我为之重定向的一些外部处理,实时, stdout/stderr 到 matlab 控制台(或将来的任何 matlab progress-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文件
基本上,用于设置一些环境变量的 execept .bat
要调用的文件如下所示:
python.exe -u preprocessing.py
python脚本
python 脚本以这种方式调用最终 processing.exe 可执行文件:
subprocess.call("processsing.exe");
下面是在 matlab 中针对 solution 指出的改编 @rahnema1 完全终止进程及其子进程(递归):
function [] = onStopProcess(process)
%[
if (double(process.HasExited())), return; end
killProcessTree(process.Id);
process.WaitForExit();
%]
end
function [] = killProcessTree(processId)
%[
%
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