fork()
和exec()
// usr/src/bin/forkexec.rs
pub fn main() -> i32 {
println!("pid {}: parent start forking ...", getpid());
let pid = fork(); // 创建子进程
if pid == 0 {
// 子进程
println!("pid {}: forked child start execing hello_world app ... ", getpid());
exec("hello_world"); // 执行hello_world程序
100
} else {
// 父进程
let mut exit_code: i32 = 0;
println!("pid {}: ready waiting child ...", getpid());
assert_eq!(pid, wait(&mut exit_code)); //确认等待的子进程PID
assert_eq!(exit_code, 0); //确认退出码是0
println!("pid {}: got child info:: pid {}, exit code: {}", getpid() , pid, exit_code);
0
}
}
fork()
和exec()
执行结果
Rust user shell
>> forkexec
pid 2: parent start forking ...
pid 2: ready waiting child ...
pid 3: forked child start execing hello_world app ...
pid 3: Hello world from user mode program!
pid 2: got child info:: pid 3, exit code: 0
Shell: Process 2 exited with code 0
>> QEMU: Terminated
提纲
2.1 进程管理系统调用
2.3 进程创建和程序加载
2.4 进程等待与退出
提纲
2.1 进程管理系统调用
2.2 进程控制块PCB
2.4 进程等待与退出
CreateProcess(filename)
CreateProcess(filename, CLOSE_FD)
CreateProcess(filename, CLOSE_FD, new_envp)
Unix进程创建/加载系统调用: fork/exec
int pid = fork(); // 创建子进程
if(pid == 0) { // 子进程在这里继续
// Do anything (unmap memory, close net connections…)
exec(“program”, argc, argv0, argv1, …);
}
int pid = fork(); // 创建子进程
if(pid == 0) { // 子进程在这里继续
// Do anything (unmap memory, close net connections…)
exec(“program”, argc, argv0, argv1, …);
}
fork()
的执行过程main()
…
int pid = fork(); // 创建子进程
if (pid == 0) { // 子进程在这里继续
exec_status = exec(“calc”, argc, argv0, argv1, …);
printf(“Why would I execute?”); // 这行代码能执行到吗???
} else { // 父进程在这里继续
printf(“Whose your daddy?”);
…
child_status = wait(pid);
}
main()
…
int pid = fork(); // 创建子进程
if (pid == 0) { // 子进程在这里继续
exec_status = exec(“calc”, argc, argv0, argv1, …);
printf(“Why would I execute?”);
} else { // 父进程在这里继续
printf(“Whose your daddy?”);
…
child_status = wait(pid);
}
if (pid < 0) { /* error occurred */
在shell中调用fork()后加载计算器
在shell中调用fork()后加载计算器
在shell中调用fork()后加载计算器
在shell中调用fork()后加载计算器
在shell中调用fork()后加载计算器
在shell中调用fork()后加载计算器
fork()
int main() {
pid_t pid;
int i;
for (i=0; i<LOOP; i++){
/* fork another process */
pid = fork();
if (pid < 0) { /*error occurred */
fprintf(stderr, “Fork Failed”);
exit(-1);
}
else if (pid == 0) { /* child process */
fprintf(stdout, “i=%d, pid=%d, parent pid=%d\n”,I, getpid() ,getppid());
}
}
wait(NULL);
exit(0);
}
fork()
提纲
2.1 进程管理系统调用
2.2 进程控制块PCB
2.3 进程创建和程序加载
exit()
进程管理相关的系统调用可能会影响进程的状态
提纲
The fork system call is one of Unix's great ideas.
-- https://cs61.seas.harvard.edu/site/2018/WeensyOS/
但是!
但是!
For implementation expedience [Ritchie, 1979]
结论
Please, stop teaching students that fork is good design
https://www.infoq.cn/article/BYGiWI-fxHTNvSohEUNW 当 Unix 为 PDP-11 计算机(其带有内存转换硬件,允许多个进程保留驻留)重写时,只为了在 exec 中丢弃一个进程就复制进程的全部内存就已经很没效率了。我们怀疑在 Unix 的早期发展阶段,fork 之所以能幸存下来,主要是因为程序和内存都很小(PDP-11 上有只 8 个 8 KiB 页面),内存访问速度相对于指令执行速度较快,而且它提供了一个合理的抽象。这里有两点很重要: