我生成了一个子进程:
let child = Command::new("./chromedriver")
.spawn()
.expect("Failed To Run Chromedriver");
我想在主进程终止时执行结束时杀死它。我发现这是一项艰巨的任务:
libc::atexit()
这样的东西。std::process::Child
存储为全局静态变量而不定义它。如果我简单地将 free static item without body
放在文件的开头,它会给出错误 static mut CHILD_PROCESS: std::process::Child;
。所以这是我设法产生的复杂解决方案:
static mut CHILD_PROCESS_ID: i32 = 0;
extern "C" fn kill_child() {
unsafe {
let pid: libc::pid_t = CHILD_PROCESS_ID;
libc::kill(pid, libc::SIGKILL);
}
}
fn run_chrome_driver() {
let child = Command::new("./chromedriver")
.spawn()
.expect("Failed To Run Chromedriver");
unsafe {
let id: i32 = child.id().try_into().unwrap();
CHILD_PROCESS_ID = id;
libc::atexit(kill_child);
}
}
有没有更好的方法而不使用不安全的 Rust?
atexit()
可能不是 你想要的。由于它是在 Rust 考虑进程退出后执行的,因此从其中使用any标准库 API 是不安全的。因此,将其封装在安全的 API 中几乎是不可能的。您将不得不使用不安全。
假设你有
panic = "unwind"
,最安全的选择是在main()
中有一个会杀死孩子的空投守卫。这看起来像:
use std::process::{Child, Command};
use std::sync::Mutex;
static CHILD: Mutex<Option<Child>> = Mutex::new(None);
struct KillChildGuard;
impl Drop for KillChildGuard {
fn drop(&mut self) {
let child = CHILD.lock().unwrap().take();
if let Some(mut child) = child {
child.kill().expect("failed to kill");
}
}
}
fn main() {
let _guard = KillChildGuard;
// Anywhere inside the code, even deep in functions:
let child = Command::new("./chromedriver")
.spawn()
.expect("Failed To Run Chromedriver");
*CHILD.lock().unwrap() = Some(child);
}
如果您有
panic = "abort"
,那么 atexit()
似乎是唯一的选择,但请注意上述警告。