假设有如下的代码(task_pool是存储有任务状态的数据库):
let child = Command::new("ffmpeg")
.args(&[
"-i",
&src_video_name,
"-vsync",
"cfr",
&dst_video_name,
])
.current_dir(working_dir)
.spawn()?;
wait_child!(child, task_pool, id);
#[macro_export]
macro_rules! wait_child {
( $child: expr, $task_pool: expr, $id: expr ) => {{
tokio::select! {
res = $child.wait() => { if res.is_err() {
$task_pool.mark_task_failed($id);
return;
} },
_ = $task_pool.is_cancelled_task($id) => {
#[allow(unused_variables)]
let kill_res = $child.kill().await;
return;
},
}
}};
}
以上代码是可行的,当在task_pool
中的该任务被标记为取消后,ffmpeg的任务当即取消。但假如使用:
let child = Command::new("cmd")
.args(&[
"/C",
"ffmpeg",
"-i",
&src_video_name,
"-vsync",
"cfr",
&dst_video_name,
])
.current_dir(working_dir)
.spawn()?;
wait_child!(child, task_pool, id);
这样就不可行了,退出的只有cmd和tokio运行时,但是ffmpeg仍然在进行工作。
以上程序包裹在tokio的运行时中,而通过rayon线程池,多进程地运行了很多类似的任务。如果暴力的panic进程,则整个进程池都会崩掉。
PS:以上只是一个例子,更麻烦的事情在于实际强制使用的是bat,不能使用类似Command::new ("ffmpeg")
的方法直接调用,不知为何只能通过cmd调用。(但是手动运行bat时,可以通过"control + C"或者关闭窗口来退出所有相关进程)
使用了很多词条搜索,都没啥有用的解答。请教各位大佬,有没有什么方法,可以解决这个问题么?
1
共 6 条评论, 1 页
评论区
写评论对对对,我完全同意。cmd会创建一个或数个新进程。
如果直接使用cmd窗口调用bat,会发现,虽然有新进程,但是新进程会监视cmd的操作,如果cmd里输入
^c
,control + c
,或者监视到cmd窗口被关闭,则子进程自动退出。(但问题是,command创建的cmd被kill后,新进程是检测不到窗口关闭这个事件的)--
👇
sikasjc: 强答一波。。不熟悉windows,猜测是跟CMD创建进程的方式有关系
“在windows上,a创建了b,b创建了c,b退出之后,c无法找到自己的爷爷进程。进程链就断了,c成为了一个顶端进程” from: https://www.zhihu.com/question/31429459/answer/51903852
感谢回答。但是原逻辑我试了行不通,
ffmpeg
可以通过这个办法进行,但是换个a.bat
就不行了。麻烦之处在于这里。--
👇
Nayaka: 提供个思路,但是手头没机器无法测试
依旧使用原逻辑,即Command::new("ffmpeg")...
正常执行与task kill返回不同的exit code, bat内用%errorlevel%处理exit code
强答一波。。不熟悉windows,猜测是跟CMD创建进程的方式有关系
“在windows上,a创建了b,b创建了c,b退出之后,c无法找到自己的爷爷进程。进程链就断了,c成为了一个顶端进程” from: https://www.zhihu.com/question/31429459/answer/51903852
提供个思路,但是手头没机器无法测试
依旧使用原逻辑,即Command::new("ffmpeg")...
正常执行与task kill返回不同的exit code, bat内用%errorlevel%处理exit code
感谢大佬!我看了下,'tokio'里在unix类平台貌似就是
kill -9
。我用的windows,它不太能行。--
👇
formoon: 在bash中这种情况要杀死进程组,kill -9 -进程组PID, 注意是进程组PID前面加一个负号。原来做golang的时候用syscall.Kill(),rust 没试过。
在bash中这种情况要杀死进程组,kill -9 -进程组PID, 注意是进程组PID前面加一个负号。原来做golang的时候用syscall.Kill(),rust 没试过。