Linux下各种特殊进程
1. 孤儿进程
1.1. 产生原因
- 父进程结束,子进程还再运行,成为孤儿进程。
- 孤儿进程会被init所领养,init进程会变为孤儿进程的父进程,为了能够释放子进程所占用的资源
- 使用
pstree
命令可以查看。 - 子进程再结束之后,可以释放用户空间,但是释放不了PCB,子进程的PCB必须由父进程进行释放,所以孤儿进程必须有父进程。
1.2. demo实现
#include <unistd.h>
#include <stdio.h>
int main(int argc,const char* argv[])
{
pid_t pid = fork();
if(pid == 0)
{
sleep(10);
printf("==Child pid = %d,,ppid = %d",getpid(),getppid());
}else
{
printf("==parent pid = %d",getpid());
}
return 0;
}
2. 僵尸进程
2.1. 产生原因
子进程结束了,但是父进程还在运行,即父进程没有及时对子进程资源进行回收,父进程不释放子进程的PCB,那么子进程就成了僵尸进程
2.2. demo
#include <unistd.h>
#include <stdio.h>
int main(int argc,const char* argv[])
{
pid_t pid = fork();
if(pid == 0)
{
// 子进程正常退出
sleep(1);
printf("==Child pid = %d,,ppid = %d\n",getpid(),getppid());
}else if(pid > 0)
{
while(1)
{
sleep(1);
printf("==parent pid = %d\n",getpid());
}
int status;
// 释放子进程资源
pid_t pr = wait(&status);
}
return 0;
}
2.3. 子进程如何查看
2.3.1 使用top查看僵尸进程
使用top命令查看时有一栏为S,如果状态为Z说明它就是僵尸进程。
Tasks: 95 total, 1 running, 94 sleeping, 0 stopped, 0 zombie
2.3.2. 从ps中查看僵尸进程
ps -e -o stat,ppid,pid,cmd | egrep '^[Zz]'
2.4. 如何避免僵尸进程
- 父进程调用
waitpid()
等函数来接收子进程退出状态 - 附近出现结束,子进程则成为孤儿进程,由Init进程管理。
- 两次fork,使用孙子进程执行当前主进程要执行的任务,这样子进程可以正常退出,孙子进程会变为孤儿进程继续执行
3. 守护进程
3.1 什么是守护进程
守护进程(Daemon Process),也就是通常说的Daemon进程,是Linux中后台服务进程,它是一个生存期较长的进程,通常独立于控制终端,并且周期性地执行某种任务或者等待处理某些发生的时间。
守护进程是个特殊的孤儿进程,这种进程脱离终端,避免进程被任何终端所产生的信息所大端,其在执行过程中的信息也不再任何终端上显示。
3.2. 创建守护进程步骤
- 调用
umask(0)
,将文件模式创建屏蔽字改为0; - 调用
fork()
,父进程退出。(原因:父进程终止可以让shell切换到前台继续等待用户输入命令。) - 在子进程中调用
setid()
,为了使进程成为新会话的受进程,成为一个进程组的组长进程 - 调用chdir()修改当前工作目录
- 关闭相应的文件描述符。
3.3. demo
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
void create_daemon()
{
// 1、 将文件模式创建屏蔽字设置为0
umask(0);
// 2、 调用fork 父进程退出
pid_t pid = 0;
if ((pid = fork()) < 0)
{
perror("fork");
exit(2);
}
if (pid > 0)
{ // father
exit(3);
}
// 3、调用setsid 创建一个新的会话
setsid();
// 4、将当前工作目录改为更目录
chdir("/");
// 5、关闭不需要的文件描述符
// NOFILE 为 <sys/param.h> 的宏定义
// NOFILE 为文件描述符最大个数,不同系统有不同限制
for(i=0; i < NOFILE; ++i)
{
close(i);
}
// 6、忽略SIGCHLD 信号
signal(SIGCHLD, SIG_IGN);
// 守护进程逻辑
while(1)
{
// Do something
}
}
int main()
{
create_daemon();
return 0;
}