进程类型
pstree查看进程树
ps -ef | 想查的运行程序
一、进程链和进程扇
1.概念
- 进程链:父进程只fork一个子进程,而子进程继续创建子进程,子进程变父进程后不能再创建子进程。简言之:创建进程后,判断父进程退出循环,子进程继续循环
- 进程扇:与进程链反过来,父进程创建多个子进程,而子进程不再创建子进程。简言之:判断子进程退出循环,父进程继续循环fork
2.创建
- 进程链创建:
/*
* 进程链构造.c
* 进程链构造
*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int counter = 0; //记录进程个数
if(argc<2)counter = 2;
else counter = atoi(argv[1]);
int i=1; //减掉一个本身启动的进程
pid_t pid;
for(; i<counter; ++i){
pid = fork(); //循环创建进程
if(pid<0){perror("fork error");exit(1);}
else if(pid>0)break;
//父进程退出循环,子进程继续循环
}
printf("pid: %d, ppid: %d\n",getpid(),getppid());
sleep(2);
return 0;
}
输出
终端输入:
$ ./process_link 4
pid: 2250, ppid: 2244 //第一个为本身的启动进程,父进程为当前shell
pid: 2251, ppid: 2250
pid: 2252, ppid: 2251
pid: 2253, ppid: 2252
- 进程扇创建:
/*
* 进程扇构造.c
* 进程扇构造
*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int counter = 0; //记录进程个数
if(argc<2)counter = 2;
else counter = atoi(argv[1]);
int i=1; //减掉一个本身启动的进程
pid_t pid;
for(; i<counter; ++i){
pid = fork(); //循环创建进程,注意不能用vfork()
if(pid<0){perror("fork error");exit(1);}
else if(pid==0)break;
//子进程退出循环,父进程继续循环
}
printf("pid: %d, ppid: %d\n",getpid(),getppid());
while(1)sleep(1); //持续运行,可以在终端查看进程创建状态
return 0;
}
输出:
终端查看:
$ ps -ef | grep process_swing
pi 2635 2628 0 10:07 pts/0 00:00:00 ./process_swing 4
pi 2636 2635 0 10:07 pts/0 00:00:00 ./process_swing 4
pi 2637 2635 0 10:07 pts/0 00:00:00 ./process_swing 4
pi 2638 2635 0 10:07 pts/0 00:00:00 ./process_swing 4
pi 2649 2641 0 10:07 pts/2 00:00:00 grep --color=auto process_swing
二、僵尸进程
1.概念:
- 子进程结束但是没有完全释放内存(在内核中的task_struct(进程表项)没有释放),该进程就成为僵尸进程。
- 当僵尸进程的父进程结束后就会被init进程领养,最终被回收。
- 避免僵尸进程:
- 让僵尸进程的父进程来回收,父进程每隔一段时间来查询子进程是否结束并回收,调用wait()或者waitpid(),通知内核释放僵尸进程。
- 采用信号SIGCHLD通知处理,并在信号处理程序中调用wait函数。
- 让僵尸进程成为孤儿进程,由init进程回收。
示例:
/*
* process_zombie.c
* zombie, 子进程结束,父进程未结束,子进程内核没有释放
*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
pid_t pid;
pid = fork();
if(pid<0){perror("fork error");exit(1);}
else if(pid==0){ //child process
printf("pid: %d,ppid: %d\n", getpid(),getppid());
exit(0); //子进程结束成为僵尸进程
}
while(1)sleep(1); //父进程继续循环
exit(0);
}
输出:
终端:
$ ps -aux | grep process_zombie
pi 5160 0.0 0.0 1720 312 pts/0 S+ 12:53 0:00 ./process_zombie
pi 5161 0.0 0.0 0 0 pts/0 Z+ 12:53 0:00 [process_zombie] <defunct>
pi 5179 0.0 0.0 7348 568 pts/2 S+ 12:54 0:00 grep --color=auto process_zombie
看到defunct 就是僵尸进程
可以通过kill杀死父进程或者子进程。
$ ./process_zombie &
[1] 5294
$ pid: 5295,ppid: 5294
$ ps -ef | grep process_zombie
pi 5294 5166 0 13:03 pts/2 00:00:00 ./process_zombie
pi 5295 5294 0 13:03 pts/2 00:00:00 [process_zombie] <defunct>
pi 5297 5166 0 13:03 pts/2 00:00:00 grep --color=auto process_zombie
$ kill -9 5295
$ ps -ef | grep process_zombie
pi 5294 5166 0 13:03 pts/2 00:00:00 ./process_zombie
pi 5295 5294 0 13:03 pts/2 00:00:00 [process_zombie] <defunct>
pi 5301 5166 0 13:04 pts/2 00:00:00 grep --color=auto process_zombie
$ kill -9 5294
$ ps -ef | grep process_zombie
pi 5303 5166 0 13:04 pts/2 00:00:00 grep --color=auto process_zombie
[1]+ Killed ./process_zombie
$
- exit()说明:
- 在多个进程时.如果有时要检测上进程是否正常退出的.就要用到上个进程的返回值。
- exit(0):正常运行程序并退出程序;
- exit(1):非正常运行导致退出程序;
三、守护进程和孤儿进程
1.守护进程概念
- 守护进程(daemon守护神)是生存期长的一种进程。他们常常在系统引导装入时启动,在系统关闭时终止。
- 所有守护进程都以超级用户(用户ID为0)的优先权运行。
- 守护进程没有控制终端。
- 守护进程的父进程都是init进程。
2.孤儿进程概念
- 父进程结束,子进程就成为孤儿进程,会由1号进程(init进程)领养。
示例:
/*
* process_orphen.c
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
pid_t pid;
pid = fork();
if(pid<0){perror("fork error");exit(1);}
else if(pid>0){
printf("%d deaded\n",getpid());
exit(0); //父进程终止
}
else {
sleep(4); //当父进程先终止后,子进程成为孤儿进程
printf("pid: %d, ppid: %d\n",getpid(),getppid()); //查看当父进程终止后,孤儿进程的父进程变成谁
}
return 0;
}
输出:
终端:
$ ./process_orphen
5950 deaded
$ pid: 5951, ppid: 1
被1号进程领养