23.1 进程链和进程扇
23.1.1 概念
进程链:一个父进程构建出一个子进程,子进程再构建出子子进程,子子进程构建出子子子进程。。。。 这种就为进程链
进程扇:一个父进程构建出多个子进程,子进程都是由同一个父进程构建出来
23.1.2 进程链的构建
process_link.c
/* 创建5个进程(包括父进程) */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> int main(int argc, char *argv[])
{
int counter = ; if(argc < ) {
counter = ;
} else {
counter = atoi(argv[]);
} int i = ;
pid_t pid; //循环变量从1开始,要减去父进程,即创建4个子进程
//需要保证父进程要跳出循环,子进程去创建子子进程
for(; i < counter; i++) {
pid = fork();
if(pid < ) {
perror("fork error");
exit();
} else if(pid > ) {
break; //父进程退出循环,子进程继续做循环
}
} printf("pid : %d, ppid: %d\n", getpid(), getppid());
while() {
sleep();
} return ;
}
运行:
执行 ps -ef | grep process_link 查看进程:
注意 8468 进程编号并不是 process_link 进程,它为 shell 的进程,运行的 process_link 的进程的父进程就是shell终端
23.1.3 进程扇的构建
/* 创建5个进程(包括父进程) */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> int main(int argc, char *argv[])
{
int counter = ; if(argc < ) {
counter = ;
} else {
counter = atoi(argv[]);
} int i = ;
pid_t pid; //循环变量从1开始,要减去父进程,即创建4个子进程
//需要保证父进程要跳出循环,子进程去创建子子进程
for(; i < counter; i++) {
pid = fork();
if(pid < ) {
perror("fork error");
exit();
} else if(pid == ) {
break; //子进程退出循环,父进程继续做循环
}
} printf("pid : %d, ppid: %d\n", getpid(), getppid());
while() {
sleep();
} return ;
}
编译运行如下,
子进程对应的父进程都为 113892
23.2 守护进程和孤儿进程
进程在操作系统中根据功能分为各种各样的进程。
23.2.1 守护进程
- 守护进程(daemon)是生存期长的一种进程。它们常常在系统引导装入时启动,在系统关闭时终止。
- 所有守护进程都以超级用户(用户 ID 为0)的优先权运行
- 守护进程没有控制终端
- 守护进程的父进程都是 init 进程
23.2.2 孤儿进程
- 父进程结束,子进程就成为孤儿进程,会由 1 号进程(init 进程)领养
process_orphen.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> int main(void)
{
pid_t pid; pid = fork();
if(pid < ) {
perror("fork error");
exit();
} else if(pid > ) {
printf("%d deaded\n", getpid());
exit();
} else {
sleep();
printf("pid : %d, ppid : %d\n", getpid(), getppid());
} return ;
}
编译运行:
这里由些奇怪的地方是孤儿进程被进程 2323领养,查看下这个进程:
这个进程的作用是:用于linux开机自动启动某些后台服务,同时还承担监控这些服务运行状态的功能。
这个进程代替了 1 号进程的一些特性,如果作死想试下关闭掉这个进程,可以进入下面的链接尝试:
https://www.cnblogs.com/chilumanxi/p/5136102.html
23.2.3 僵尸进程
- 子进程结束,但是没有完全释放内存(在内核中的 task_struct 没有释放),该进程就成为僵尸进程。
- 当僵尸进程的父进程结束后,就会被 init 进程领养,最终被回收
- 避免僵尸进程
- 让僵尸进程的父进程来回收,父进程每隔一段时间来查询子进程是否结束并回收,调用 wait() 或者 waitpid() ,通知内核释放僵尸进程
- 采用信号 SIGCHLD 通知处理,并在信号处理程序中调用 wait 函数
- 让僵尸进程成为孤儿进程,由 init 进程回收
(1)构建僵尸进程
process_zombie.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> int main(void)
{
pid_t pid; pid = fork();
if(pid < ) {
perror("fork error");
exit();
} else if(pid == ) {
printf("pid : %d, ppid: %d\n", getpid(), getppid());
exit(); //子进程结束成为僵尸进程
} while() {//父进程继续循环
sleep();
} exit();
}
编译运行:
另开一终端,查看进程
114707 为父进程,为S+,即可中断运行状态
子进程为 114708,状态为 Z+,Z即代表是僵尸进程,或者看进程名的 defunct ,有这个名字也为僵尸进程