【问题标题】:Kill child process while waiting for it在等待时杀死子进程
【发布时间】:2016-01-29 20:53:48
【问题描述】:

我想执行另一个进程,通常想等到它完成。假设我们在线程 T1 中生成并等待进程:

let child = Command::new("rustc").spawn().unwrap();
child.wait();

现在,如果发生特殊事件(T0 正在等待哪个线程),我想终止生成的进程:

if let Ok(event) = special_event_notifier.recv() {
    child.kill();
}

但我看不出有什么办法:kill 和wait 都对Child 进行了可变引用,因此它们是互斥的。在调用wait 之后,没有人可以再引用child。

我找到了wait-timeout crate,但我想知道是否还有其他方法。

【问题讨论】:

  • 嗯,这似乎是在问题跟踪器中提出的一个好问题。
  • 从 Rust 1.18 开始可以使用 Child::try_wait() 进行忙碌等待。但这并不能真正解决问题......

标签: rust


【解决方案1】:

显然,您可以自己终止该进程。 Child::id 方法为您提供了足够的“操作系统分配的进程标识符”。

唯一的问题是杀死一个进程是一个依赖于平台的操作。在 UNIX 上,终止进程是使用 kill 函数处理的:

#![feature(libc)]
extern crate libc;
use std::env::args;
use std::process::Command;
use std::thread::{spawn, sleep};
use std::time::Duration;
use libc::{kill, SIGTERM};

fn main() {
    let mut child = Command::new("/bin/sh").arg("-c").arg("sleep 1; echo foo").spawn().unwrap();
    let child_id = child.id();
    if args().any(|arg| arg == "--kill") {
        spawn(move || {
            sleep(Duration::from_millis(100));
            unsafe {
                kill(child_id as i32, SIGTERM);
            }
        });
    }
    child.wait().unwrap();
}

在 Windows 上,您可以尝试 OpenProcess 和 TerminateProcess 函数(在 kernel32-sys crate 中可用)。

【讨论】:

    【解决方案2】:

    如果子子进程在完成之前没有关闭 stdout,则可以等待读取 stdout。这是一个例子

    use std::io::Read;
    use std::process::*;
    use std::thread;
    use std::time::Duration;
    
    fn wait_on_output(mut out: ChildStdout) {
        while out.read_exact(&mut [0; 1024]).is_ok() { }
    }
    
    fn wait_or_kill(cmd: &mut Command, max: Duration) {
        let mut child = cmd.stdout(Stdio::piped())
                           .spawn()
                           .expect("Cannot spawn child");
    
        let out = child.stdout.take().expect("No stdout on child");
    
        let h = thread::spawn(move || {
            thread::sleep(max);
            child.kill().expect("Cannot kill child");
            println!("{:?}", child.wait());
        });
    
        wait_on_output(out);
        h.join().expect("join fail");
    }
    
    fn main() {
        wait_or_kill(Command::new("sleep").arg("1"), Duration::new(2, 0));
        wait_or_kill(Command::new("sleep").arg("3"), Duration::new(2, 0));
    }
    

    这个程序在我的系统上的输出是

    Ok(ExitStatus(ExitStatus(0)))
    Ok(ExitStatus(ExitStatus(9)))
    

    虽然不在文档中,但杀死完成的孩子会返回 Ok。

    这是有效的,因为杀死一个进程会关闭与其关联的文件。但是,如果子进程产生新进程,杀死子进程可能不会杀死这些其他进程,它们可能会保持标准输出处于打开状态。

    【讨论】:

      猜你喜欢
      • 2018-03-08
      • 1970-01-01
      • 2010-12-08
      • 1970-01-01
      • 1970-01-01
      • 2013-07-27
      • 1970-01-01
      • 1970-01-01
      • 2016-11-20
      相关资源
      最近更新 更多