【发布时间】:2020-07-19 08:54:02
【问题描述】:
我目前正在编写一个同时启动其他应用程序的应用程序(例如firefox)。我希望这些子应用程序比父应用程序寿命更长(例如,当父应用程序退出时它们应该继续运行)。只要父进程自行退出(主进程结束,process:exit()),这就是有效的,但是如果父进程收到SIGINT(ctrl + c),SIGTERM 所有子进程都会立即死亡,因为好。我怎样才能避免这种情况? 注意:我的主要过程旨在长期存在,因此下面所有在产卵后立即退出的示例都不适合我的情况,我只是为了完整性而列出它们以显示我的内容试过了,等等
目前我只关心 Linux 支持,前提是没有干净的跨平台解决方案。
到目前为止,我已经尝试了以下方法,但没有一个让我满意:
use std::{
process::{self, Child, Command, Stdio},
thread,
};
const EXECUTABLE: &str = "/usr/bin/firefox";
fn main() {
// The child continues to live after our process has finished
spawn_and_exit();
// The child continues to live after our process has cleanly finished
//spawn_and_continue()
// The child gets killed as well if our process gets killed
//spawn_and_force_shutdown()
// Child continues to live (if our process shuts down cleanly)
//threaded_clean_spawn()
// Child gets killed as well
//threaded_and_force_shutdown()
// child gets killed as well
//double_threaded_and_force_shutdown()
}
fn wait() {
std::thread::sleep(std::time::Duration::from_millis(250));
}
fn hang() {
println!("You can now kill the process (e.g. Ctrl+C)");
loop { wait(); }
}
/// The child continues to live after our process has finished
fn spawn_and_exit() {
println!("Spawn and exit");
let _child = Command::new(EXECUTABLE)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap();
// give the process some time to actually start
wait();
wait();
process::exit(0);
}
/// The child continues to live after our process has finished
fn spawn_and_continue() {
println!("Spawn and clean shutdown");
let _child = Command::new(EXECUTABLE)
//.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap();
// give the process some time to actually start
wait();
}
/// The child gets killed as well if our process gets killed
fn spawn_and_force_shutdown() {
println!("Spawn and force shutdown");
let _child = Command::new(EXECUTABLE)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap();
wait();
hang();
}
/// Child continues to live (if our process shuts down cleanly)
fn threaded_clean_spawn() {
println!("threaded_clean_spawn");
let _joinhandle = thread::Builder::new().spawn(|| {
spawn_and_continue();
});
wait();
}
/// Child gets killed as well
fn threaded_and_force_shutdown() {
println!("threaded_and_force_shutdown");
let _joinhandle = thread::Builder::new().spawn(|| {
spawn_and_continue();
});
hang();
}
/// child gets killed as well
fn double_threaded_and_force_shutdown() {
println!("double_threaded_and_force_shutdown");
let _joinhandle = thread::Builder::new().spawn(|| {
let joinhandle = thread::Builder::new().spawn(move || {
spawn_and_continue();
}).unwrap();
let _ = joinhandle.join();
println!("inner thing returned");
});
hang();
}
旁注:最初,我预计 thread::Builder::new().spawn() 会解决我的问题,因为文档 (https://doc.rust-lang.org/std/thread/struct.Builder.html#method.spawn) 指出:
生成的线程可能比调用者活得更久(除非调用者线程是主线程;当主线程完成时整个进程终止)。
由于括号中的加法,我也尝试了double_threaded_and_force_shutdown的方法,没有成功。
这与How to Spawn Child Processes that Don't Die with Parent? 基本上是相同的问题,但针对的是 Rust 而不是 c++。
【问题讨论】:
-
@SvetlinZarev 不幸的是没有。帖子说“这样做的传统方法是分叉两次。”但我用我的最后一个功能做到了这一点,它也不能正常工作。该帖子还说(就像我在帖子中链接的问题一样)“您需要调用setsid()”,但我不知道如何从生锈中做到这一点?
-
正如您所说,如果您主要对 Linux 感兴趣,那么您可以使用
nixcrate 调用setsid: docs.rs/nix/0.17.0/nix/unistd/fn.setsid.html 在您的示例代码中,您从未分叉过两次。创建两个线程是不一样的。在 rust 中,当主线程退出时,所有线程都会被销毁。
标签: linux rust fork parent-child spawn