【问题标题】:How do I ensure that a spawned Child process is killed if my app panics?如果我的应用程序出现恐慌,如何确保生成的子进程被杀死?
【发布时间】:2015-08-12 19:37:08
【问题描述】:

我正在编写一个启动守护进程并对其进行测试的小测试,例如:

let server = Command::new("target/debug/server").spawn();

// do some tests

server.kill();

测试失败的典型方式是恐慌。不幸的是,这意味着 kill() 永远不会被调用,并且测试套件的重复运行会失败,因为端口被仍在运行的旧进程占用。

我可以使用类似 TRAP 的函数来确保 Child 被杀死吗?

【问题讨论】:

    标签: rust child-process zombie-process


    【解决方案1】:

    您可以将可能引起恐慌的代码放入一个闭包中,并将该闭包交给catch_paniccatch_panic 的作用与scopedspawned 线程对joining 的作用相同。如果闭包发生恐慌,它会返回带有Ok(ClosureRetVal)Err(Box<Any>) 的结果。

    let res = std::thread::catch_panic(|| {
        panic!("blub: {}", 35);
    });
    if let Err(err) = res {
        let msg: String = *err.downcast().unwrap();
        println!("{}", msg);
    }
    

    PlayPen

    【讨论】:

      【解决方案2】:

      您可以使用标准 RAII 模式来确保在您离开给定范围时终止子线程。如果您只想在惊慌失措的情况下杀死您的孩子,您可以将支票插入std::thread::panicking

      use std::process::{Command,Child};
      
      struct ChildGuard(Child);
      
      impl Drop for ChildGuard {
          fn drop(&mut self) {
              // You can check std::thread::panicking() here
              match self.0.kill() {
                  Err(e) => println!("Could not kill child process: {}", e),
                  Ok(_) => println!("Successfully killed child process"),
              }
          }
      }
      
      fn main() {
          let child = Command::new("/bin/cat").spawn().unwrap();
          let _guard = ChildGuard(child);
      
          panic!("Main thread panicking");
      }
      

      【讨论】:

      • 如果线程恐慌,Drop 实现是否保证运行?
      • 我想是的,除非恐慌是在析构函数(playpen)开始 的,这在Rust 中无论如何都是一个坏主意,原因有很多。 std::rt::unwind 中有一些关于展开过程如何发生的文档。
      • 谢谢,这就是我最终做的事情。虽然现在因为我曾经拥有它,但似乎无法执行 Drop 特征。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-19
      • 1970-01-01
      • 2011-09-23
      • 1970-01-01
      • 1970-01-01
      • 2011-08-17
      • 2010-12-08
      相关资源
      最近更新 更多