一、前言
前面结束过使用fork()
创建多个进程,使用sem_open()
, sem_wait()
, sem_post()
保护临界区资源。
但是遗漏了一个重要的事情,如果调用fork()
之后,父进程先结束了。本来要在父进程里面做些清理工作。这时候就尴尬了
爸爸process没了,儿子process还在。
二、演示父进程先结束
1.Cargo.toml 配置
1
2
|
[dependencies]
nix = "0.16.1"
|
2. 父进程结束,子进程不结束–最小化example
下面的代码会先输出
Continuing execution in parent process, new child has pid
bye bye main!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
//use nix::sys::wait;
use nix::unistd::{fork, ForkResult};
use std::{thread, time};
fn main() {
match fork() {
// 父进程
Ok(ForkResult::Parent { child, .. }) => {
println!(
"Continuing execution in parent process, new child has pid: {}",
child
);
}
// 子进程
Ok(ForkResult::Child) => {
let sec = time::Duration::from_secs(10);
thread::sleep(sec);
println!("I'm a new child process")
}
Err(err) => println!("Fork failed:{}", err),
}
//match wait::wait() {
// Ok(status) => println!("Child exited with status {:?}", status),
// Err(err) => panic!("waitpid() failed: {}", err),
//}
println!("bye bye main !")
}
|
三、父进程等待子进程先结束
要变成父进程等待子进程结束然后退出。只要把上面的注释去掉就行。这里揭晓下谜底wait()
system call
man 说明文档
The wait() system call suspends execution of the calling process until one of its children terminates. The call wait(&wstatus) is equivalent to:
waitpid(-1, &wstatus, 0);
四、在rust实现erlang的哲学
已经有fork和wait,我们也许可以实现下erlang的哲学理念.
1.回顾下erlang的哲学
-
让其它进程来修复错误。
-
工作者不成功,便成仁。(if you can’t do what you want to do, die.)
-
任它崩溃。
-
杜绝防御式编程。
2.解析erlang哲学
第一点可以理解为,如果监控到work进程崩溃,fork新的work 进程继续干活。2,3,4只是一个态度,好办.
3.Cargo.toml
1
2
|
[dependencies]
nix = "0.16.1"
|
4.任他奔溃,工作者不成功,便成仁
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
use nix::sys::wait;
use nix::unistd::{fork, ForkResult};
use std::{thread, time};
fn proc_new() {
match fork() {
// 父进程
Ok(ForkResult::Parent { child, .. }) => {
println!(
"Continuing execution in parent process, new child has pid: {}",
child
);
}
// 子进程
Ok(ForkResult::Child) => {
let sec = time::Duration::from_secs(3);
thread::sleep(sec);
println!("I'm a new child process");
// 模拟coredump 或者段错误
panic!("child process dead");
}
Err(err) => println!("Fork failed:{}", err),
}
}
fn main() {
proc_new();
// 监控子进程状态
loop {
match wait::wait() {
Ok(status) => {
println!("Child exited with status {:?}", status);
proc_new();
}
Err(err) => panic!("waitpid() failed: {}", err),
}
}
}
|
5. ps命令测试
撸码的最后一个环境是测试。这里使用``ps```测试以上代码是否都保持在2个进程
1
2
3
4
|
s aux |grep use_
# 输出
# guo 12288 0.0 0.0 13304 1012 pts/3 S+ 14:44 0:00 ./target/debug/use_fork_wait
# guo 12297 0.0 0.0 13304 136 pts/3 S+ 14:45 0:00 ./target/debug/use_fork_wait
|
6. 还可以优化的地方
使用wait()
监控子进程状态,然后fork进程,这里根据错误数设计滑动窗口,削峰填谷。解决系统的抖动。
五、参考资料
https://iximiuz.com/en/posts/dealing-with-processes-termination-in-Linux/