1. 僵尸进程
1.1 僵尸进程的定义:
父进程创建了子进程,而子进程先于父进程结束,子进程的资源没有被释放,就会变成僵尸进程,持续占用系统资源
1.2 僵尸进程的解决办法
子进程在结束之前会向父进程发送SIGCHLD信号,父进程接收到信号之后,先回收子进程资源,然后父进程自己再结束
想要防止僵尸进程的情况出现,可以在父进程中写一个wait函数(或者waitpid函数)等待子进程发送的SIGCHLD信号
无wait()函数的情况:
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(){
if(fork()){
printf("子进程被创建!\n");
}else{
for(int i = 0;i<5;i++){
printf("子进程执行:%d\n",i+1);
sleep(1);
}
}
printf("父进程结束!\n\n");
return 0;
}
运行结果:
从上面的输出结果可以看出,在没有wait()函数的情况下,父进程并不会等待子进程结束之后再执行"父进程结束!"这句话,如果在此时父进程在子进程未结束前被强制结束,那么就会造成僵尸进程的情况出现
有wait()函数的情况:
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(){
if(fork()){
printf("子进程被创建!\n");
wait(0);
}else{
for(int i = 0;i<5;i++){
printf("子进程执行:%d\n",i+1);
sleep(1);
}
}
printf("父进程结束!\n\n");
return 0;
}
运行结果:
当存在wait()函数时,父进程会等待子进程发送的SIGCHLD信号,当父进程接收到信号之后,先回收子进程资源,父进程再结束
2.守护进程
2.1 守护进程概念
独立记录其它进程的情况,记录操作系统日志等
2.2 守护进程的查看方法
ps -axj
TPGID为 -1 的是守护进程
2.3 守护进程的创建
2.3.1 守护进程的功能实现和其它进程一样
2.3.2 将一个进程变为守护进程的步骤
- 干掉其父进程
- 摆脱终端控制(关闭0 1 2 文件描述符并重定向当前进程的io操作到 /dev/NULL (黑洞设备))
- 摆脱原有会话,进程组的控制从而创建新的会话
2.4 创建守护进程编程模型
2.4.1 创建守护进程方式一
- 创建新会话 setsid()函数
- 改变当前工作目录 chdir()函数
- 重设当前文件权限 umask()函数
关闭文件 close()函数
2.4.2 创建守护进程方式二
重设文件权限 umask()函数
- 创建子进程 fork()函数
- 结束父进程
- 创建新会话 setsid()
- 防止子进程成为僵尸进程 signal()函数忽略掉SIGCHLD SIGHUP信号
- 改变当前工作目录 chdir()函数
- 重定向文件描述符号 open()函数 dup2()函数
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
int main(){
// 1. 重设文件权限
umask(0);
// 2. 创建子进程
int ret = fork();
if(ret < 0) printf("创建进程失败:%m"),exit(-1);
if(ret > 0) printf("父进程结束:%m\n"),exit(0); // 3. 让父进程结束
if(0 == ret){
printf("pid:%d\n",getpid());
// 4. 创建新会话
setsid();
// 5. 防止子进程成为僵尸进程 忽略掉SIGCHLD SIGHUP信号
signal(SIGCHLD,SIG_IGN);
signal(SIGHUP,SIG_IGN);
// 6. 改变当前工作目录
chdir("/");
// 7. 重定向文件描述符号
int fd = open("/dev/NULL",O_RDWR);
dup2(fd,0);
dup2(fd,1);
}
while(1){
//做事情(模拟守护进程工作)
sleep(1);
}
return 0;
}
结果:
关闭守护进程:
由此可知上方创建的pid为3469的守护进程已经被关闭
2.5 进程的组织形式
多个进程组成一个进程组
多个进程组组成一个会话
注: 进程组的组长 session进程
2.6 守护进程的关闭
直接使用kill 2 pid 将指定进程干掉即可
2.7 终端标准输入输出设备
- 0 标准输入设备
- 1 标准输出设备
- 2 标准错误输出设备