C语言之进程控制(僵尸进程和守护进程)
2017-08-09 20:41
344 查看
进程控制编程
1、子进程先父进程先结束:如果子进程结束的时候,父进程不做任何处理,那么这个子进程的一些信息会被保留,比如子进程的文件描述符,此时的子进程会被称为僵尸进程。这种僵尸进程会给程序带来不可想象的伤害,所以我们要尽量避免僵尸进程的产生。
僵尸进程产生的过程:
(1)父进程调用fork创建子进程后,子进程运行直至其终止,它立即从内存中移除,但进程描述符仍然保留在内存中(进程描述符占有极少的内存空间)。
(2)子进程的状态变成EXIT_ZOMBIE,并且向父进程发送SIGCHLD 信号,父进程此时应该调用 wait() 系统调用来获取子进程的退出状态以及其它的信息。在 wait 调用之后,僵尸进程就完全从内存中移除。
(3)因此一个僵尸存在于其终止到父进程调用 wait 等函数这个时间的间隙,一般很快就消失,但如果编程不合理,父进程从不调用 wait 等系统调用来收集僵尸进程,那么这些进程会一直存在内存中。
(4)僵尸进程的处理一般是用wait()函数来处理。
代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int main()
{
pid_t pid = fork(); //fork产生子进程,返回值pid如果是-1代表错误,0则代表子进程,非0代表的是父进程。
//fork很特殊,它会复制父进程,然后在父进程中返回的是子进程的ID号,而在子进程中是返回的0;
switch(pid)
{
case -1:
perror("fork");
exit(0);
case 0:
printf("我是子进程\n");
break; //子进程先父进程结束,产生僵尸进程
default:
printf("我是父进程\n");
while(1); //死循环防止父进程结束。
break;
}
return 0;
}
2、父进程先子进程先结束:则该父进程的所有子进程的父进程都改变为init进程。我们称这些进程由init进程领养。其执行顺序大致如下:在一个进程终止时,内核逐个检查所有活动进程,以判断它是否是正要终止的进程的子进程,如果是,则该进程的父进程ID就更改为1(init进程的ID);
有init领养的进程不会称为僵死进程,因为只要init的子进程终止,init就会调用一个wait函数取得其终止状态。这样也就防止了在系统中有很多僵死进程。
如果父进程结束,那么子进程会被init进程领养,那么这个时候我们就不能直接对这个子进程进行操作了,这个时候这个子进程会在后台继续运行,这个时候我们称这个子进程为守护进程(或者精灵进程)。在计算机中,有很多的后台程序在运行,所以这个守护进程对我们来说是很重要的。
1、子进程先父进程先结束:如果子进程结束的时候,父进程不做任何处理,那么这个子进程的一些信息会被保留,比如子进程的文件描述符,此时的子进程会被称为僵尸进程。这种僵尸进程会给程序带来不可想象的伤害,所以我们要尽量避免僵尸进程的产生。
僵尸进程产生的过程:
(1)父进程调用fork创建子进程后,子进程运行直至其终止,它立即从内存中移除,但进程描述符仍然保留在内存中(进程描述符占有极少的内存空间)。
(2)子进程的状态变成EXIT_ZOMBIE,并且向父进程发送SIGCHLD 信号,父进程此时应该调用 wait() 系统调用来获取子进程的退出状态以及其它的信息。在 wait 调用之后,僵尸进程就完全从内存中移除。
(3)因此一个僵尸存在于其终止到父进程调用 wait 等函数这个时间的间隙,一般很快就消失,但如果编程不合理,父进程从不调用 wait 等系统调用来收集僵尸进程,那么这些进程会一直存在内存中。
(4)僵尸进程的处理一般是用wait()函数来处理。
代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int main()
{
pid_t pid = fork(); //fork产生子进程,返回值pid如果是-1代表错误,0则代表子进程,非0代表的是父进程。
//fork很特殊,它会复制父进程,然后在父进程中返回的是子进程的ID号,而在子进程中是返回的0;
switch(pid)
{
case -1:
perror("fork");
exit(0);
case 0:
printf("我是子进程\n");
break; //子进程先父进程结束,产生僵尸进程
default:
printf("我是父进程\n");
while(1); //死循环防止父进程结束。
break;
}
return 0;
}
2、父进程先子进程先结束:则该父进程的所有子进程的父进程都改变为init进程。我们称这些进程由init进程领养。其执行顺序大致如下:在一个进程终止时,内核逐个检查所有活动进程,以判断它是否是正要终止的进程的子进程,如果是,则该进程的父进程ID就更改为1(init进程的ID);
有init领养的进程不会称为僵死进程,因为只要init的子进程终止,init就会调用一个wait函数取得其终止状态。这样也就防止了在系统中有很多僵死进程。
如果父进程结束,那么子进程会被init进程领养,那么这个时候我们就不能直接对这个子进程进行操作了,这个时候这个子进程会在后台继续运行,这个时候我们称这个子进程为守护进程(或者精灵进程)。在计算机中,有很多的后台程序在运行,所以这个守护进程对我们来说是很重要的。
守护进程的代码: #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <stdlib.h> #include <sys/stat.h> #include <fcntl.h> int Daemonize() { pid_t pid = fork(); //创建子进程 if(pid == -1) { perror("fork"); return -1; } else if(pid > 0) { exit(0); //关闭父进程 } umask(0); //设置文件的掩码。 /*注释:文件权限掩码是指屏蔽掉文件权限中的对应位。比如,有个文件权限掩码是050,它就屏蔽了文件组拥有者的可读与可执行权限。由于使用fork函数新建的子进程继承了父进程的文件权限掩码,这就给该子进程使用文件带来了诸多的麻烦。因此,把文件权限掩码设置为0,可以大大增强该守护进程的灵活性。*/ if(setsid < 0) //设置新的会话,目的是让这个子进程从父进程脱离出来,不受任何父进程控制。 { perror("setsid"); return -1; } if(chdir("/") == -1) //设置当前的工作目录。 { perror("chdir"); return -1; } close(0); //关闭标志输入,标志输出,标准错误,不让它在终端显示打印信息。 close(1); close(2); open("dev/null",O_RDONLY); //文件的重定向,让这个守护进程的信息打印在一个文件里 open("dev/null",O_RDWR); open("dev/null",O_RDWR); return 0; } int main() { Daemonize(); //守护进程函数 while(1); //死循环 return 0; }
相关文章推荐
- 进程控制编程之僵尸进程、守护进程创建、进程等待
- 浅析三种特殊进程:孤儿进程,僵尸进程和守护进程.
- 孤儿进程,僵尸进程,守护进程的剖析
- linux下tcpwraper和xinetd超级守护进程访问控制详解
- 孤儿进程&僵尸进程&守护进程【详细实例总结】
- 守护进程与僵尸进程
- 在linux或者unix操作系统中在系统的引导的时候会开启很多服务,这些服务就叫做守护进程。守护进程是在后台运行不与任何控制终端关联,是Linux中的后台服务进程。它是一个生存期较长的进程,通常独立于
- 进程组、会话、控制终端和守护进程
- Linux进程控制编程之守护进程
- Linux进程控制及守护进程
- 终端,作业控制与守护进程
- 进程控制3 守护进程 华清远见-《嵌入式 Linux 应用程序开发标准教程》
- 守护进程和僵尸进程
- 控制终端 会话 进程组 守护进程
- rhel7 systemd控制服务和守护进程
- 进程控制:结束进程、等待进程结束、避免僵尸进程
- 【Redis】redis开机自启动、设置守护进程、密码设置、访问权限控制等安全设置(redis默认端口6379)
- 进程组,会话,控制终端,守护进程(请大家指教)
- 进程、僵尸进程、孤儿进程、进程组、前台进程组、后台进程组、孤儿进程组、会话、控制终端http://blog.csdn.net/hmsiwtv/article/details/7901711
- Unix环境高级编程:进程控制-线程控制-僵尸进程