1.fork()
fork创建一个新进程。这个系统调用复制当前进程,在进程表中创建一个新的表项,新进程几乎与原进程一模一样,执行的代码也是完全一样,但新进程有自己的数据空间、环境、文件描述符。
返回值:#include<sys/types.h> #include<unistd.h> pid_t fork(void);
- 如果成功创建一个子进程,对于父进程来说返回子进程ID
- 如果成功创建一个子进程,对于子进程来说返回值为0
- 如果为-1表示创建失败
- 使用fork函数得到的子进程从父进程的继承了整个进程的地址空间,包括:进程上下文、进程堆栈、内存信息、打开的文件描述符、信号控制设置、进程优先级、进程组号、当前工作目录、根目录、资源限制、控制终端等。
- 子进程与父进程的区别在于:
- 1、父进程设置的锁,子进程不继承
- 2、各自的进程ID和父进程ID不同
- 3、子进程的未决告警被清除;
- 4、子进程的未决信号集设置为空集。
3. fork系统调用需要注意的地方
- fork系统调用之后,父子进程将交替执行。
- 如果父进程先退出,子进程还没退出那么子进程的父进程将变为init进程。(注:任何一个进程都必须有父进程)
- 如果子进程先退出,父进程还没退出,那么子进程必须等到父进程捕获到了子进程的退出状态才真正结束,否则这个时候子进程就成为僵进程。
- 子进程退出会发送SIGCHLD信号给父进程,可以选择忽略或使用信号处理函数接收处理就可以避免僵尸进程。
一个fork的例子/*fork.c*/ #include<stdio.h> #include<unistd.h> #include<sys/types.h> int main() { pid_t pid; char *message; pid=fork(); if(pid<0) { perror("fork error!"); exit(1); } else if(pid>0) { message="this is parent!"; printf("%s ppid=%d\n",message,pid); } else { message="this is child!"; printf("%s ppid=%d\n",message,pid); } return 0; }
结果是:make fork ./fork1
结果是乱的,别急我们来看第二个函数;this is parent! ppid=2486 zhou@hyn-virtual-machine:~/os/test/test1/daemon$ this is child! ppid=0
2.wait()
在例程fork1.c中由于父进程先于子进程结束;所以输出结果有点乱,我们可以在父进程中调用wait()等待子进程结束;
#include<sys/types.h> #include<sys/wait.h> pid_t wait(int *stat_loc);
wait()会暂时停止进程的执行,直到有信号来到或子进程结束。如果在调用wait()时子进程已经结束,则wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数status 返回,而子进程的进程识别码也会一起返回。如果不在意结束状态值,则参数status 可以设成NULL。
结束状态值信息:
- WIFEXITED(stat_val)如果子进程正常结束,他就取一个非零值
- WEXITSTATUS(stat_val)如果WIFEXITED非零,他返回子进程的退出码
- WIFSIGNALED(stat_val)如果子进程因为一个未捕获的信号而终止,他就取一个非零值
- WTERMSIG(stat_val)如果WIFSIGNALED非零,他返回一个信号代码
- WIFSTOPPED(stat_val)如果子进程意外终止,它就取一个非零值
- WSTOPSIG(stat_val)如果WIFSTOPPED非零,他返回一个信号代码
一个wait的例子
/*wait.c*/ #include<stdio.h> #include<unistd.h> #include<sys/types.h> #include<sys/wait.h> int main() { pid_t pid; char *message; pid=fork(); int exit_code; if(pid<0) { perror("fork error!"); exit(1); } else if(pid>0) { message="this is parent!"; printf("%s ppid=%d\n",message,pid); int stat_val; pid_t child_pid; child_pid=wait(&stat_val); if(WIFEXITED(stat_val)) { printf("child exited with code%d\n",WEXITSTATUS(stat_val)); } else { printf("child terminated abnormally\n"); } } else { message="this is child!"; printf("%s ppid=%d\n",message,pid); exit_code=37; } exit(exit_code); }
make wait ./wait
结果是this is parent! ppid=2576 this is child! ppid=0 child exited with code37