1)孤儿进程
父进程退出,子进程不退出。子进程会被1号进程(init进程)收养,脱离终端控制。
孤儿进程不能用ctrl + c退出,但是可以被kill -9杀死。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, const char *argv[])
{
if(fork() == 0)
{
//子进程运行
while(1)
{
printf("child %d %d\n", getppid(), getpid());
sleep(1);
}
}
return 0;
}
2)僵尸进程
父进程不退出,子进程退出,且子进程的资源没有被回收,此时子进程就是僵尸进程。
注意:
i. 僵尸进程是已经死掉的进程,所以无法再被杀死(kill),但是可以被回收。
ii. 可以用wait/waitpid函数回收
iii. 父进程退出后,子进程的资源将由内核自动回收。
iv. 僵尸进程是有危害的,如果不回收,会占用资源。例如:占用进程号,占用内存空间,
占用物理空间,占用进程调度机制等等... .....。所以僵尸进程必须回收。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, const char *argv[])
{
if(fork() > 0)
{
//父进程运行
while(1)
{
printf("parent %d\n", getpid());
sleep(1);
}
}
return 0;
}
3)守护进程(幽灵进程)
- 守护进程是脱离于终端并且运行在后台的进程。
- 当需要周期性执行某些任务的时候,一般使用守护进程,因为运行在后端不会影响前端的使用。
- 守护进程在执行过程中不会将信息显示到任何终端上,防止对用户在使用终端的时候产生影响,并且不会被终端的任何中断信息打断,例如ctrl+c。
守护进程的创建步骤:
- 创建一个孤儿进程:所有工作在子进程中执行。 fork(), 退出父进程
- 创建新的进程组和会话组:让子进程完全独立。 setsid()
- 修改当前孤儿进程的运行目录为不可卸载的文件系统。例如根目录,若有日志要输出,一般运行在/tmp下 chdir()函数
- 重设文件权限掩码:将文件权限掩码清0: umask(0)。保留设置时候的文件权限, umask(0);
- 关闭所有从父进程继承过来的文件描述符:继承到的文件描述符不会使用,浪费资源,所以要关闭
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, const char *argv[])
{
//创建一个孤儿进程
if(fork() == 0)
{
//创建新的进程组 会话组
pid_t sid = setsid();
printf("sid = %d\n", sid);
//修改运行目录为不可卸载的文件
chdir("/");
//将umask清0
umask(0);
//关闭所有文件描述符
for(int i=0; i<getdtablesize(); i++)
{
close(i);
}
while(1)
{
//功能代码
sleep(1);
}
}
return 0;
}