CSAPP之fork
导读
Unix提供了大量从C程序中操作进程的系统调用。
相关知识
1.相关函数
- getpid() — 返回当前的进程PID
- waitpid(pid_t pid,int *statusp,int options) — PID:
pid>0时只等待ID为pid的子进程结束
pid=-1时等待其所有的子进程中任何一个结束
options:
options=0,挂起父进程,等待子进程结束。返回子进程PID
options=WNOHANG时,父进程不挂起没有子进程结束的话,返回0,否则返回子进程的PID - atexit() — 在进程结束调用exit()时候调用,括号内的函数,调用顺序和登记顺序相反,类似栈
2.创建和终止进程
从程序猿的角度,我们可以认为进程总是处在下面三种状态之一
- 运行
- 停止 — 进程的执行被挂起,且不会被调度
- 终止 — 1)收到信号 2)从主程序返回 3)调用exit函数
正文
定义
fork:创建新的运行的子进程
解析
-
fork函数调用一次,返回两次。
-
返回的两次一次是在父进程中,fork返回子进程的PID;一次是在子进程中,fork返回0。
-
其中,子进程的PID总是为0,其余大于0的数都为父进程的PID,由此返回值就提供一个明确的方法来分辨程序是在父进程还是子进程中进行的。
-
PID就是进程ID,每个进程都有一个唯一的正数(非零)进程ID。
注意 :
1.fork系统调用之后父进程和子进程是交替执行,父子进程是处于不同空间中的。
2.fork系统调用的一次调用存在两次返回,此时二个进程处于独立的空间,各自执行自己的参数。
实例-1
-
void fork0() { if (fork() == 0) { printf("Hello from child\n"); } else { printf("Hello from parent\n"); } }
结果
-
Hello from parent Hello from child
可以看出,有两次输出;第一次到fork()==0的时候,是在父进程中执行,因为返回的不为0(子进程PID不为0),所有执行else后面语句;之后到子进程中(子进程跟父进程几乎一样),这时是在子进程中,所以fork返回0,执行child语句。
实例-2
-
void fork1() { int x = 1; pid_t pid = fork(); if (pid == 0) { printf("Child has x = %d\n", ++x); } else { printf("Parent has x = %d\n", --x); } printf("Bye from process %d with x = %d\n", getpid(), x); }
结果:
-
Parent has x = 0 Bye from progrss 1977 with x = 0 Child has x = 2 Bye from progress 1978 with x = 2
可以看出,使用fork()后,第一次是在父进程中执行,pid!=0(为子进程PID),所以执行–x和父进程PID(ppid)。
重点来了,之后到了子进程中:因为子进程里面内容(代码、数据)跟父进程一样,所有子进程里面的x还是=1(就是独立的副本),返回pid=0,执行++x和子进程的pid;可以看出子进程和父进程的ID是连着一起的,子进程PID就是父进程加1
实例-3
-
#include "csapp.h" void doit() { Fork(); Fork(); printf("hello\n"); return; } int main() { doit(); printf("hello\n"); exit(0); }
结果:
原理同上;
、、、
总结
fork 的核心思想就是fork一次,两次输出
图