一、守护进程是什么
守护进程是生存期很长的一种进程,可以说它是7*24小时工作的。(什么是7*24,一周7天,每天24小时,这不就是一年365天一直在工作嘛,还搞的这么诙谐,哈哈)。它们常常在系统引导装入时启动,仅在系统关闭时才终止。因为它们没有控制终端,所以说它们是在后台运行的,而且它没法直接和用户交互。当然在后台运行的可不一定是守护进程哦。Unix下有很多守护进程,执行日常事务。守护进程是一种很有用的进程,Linux下的很多服务器大多是用守护进程实现的。比如Internet服务器inetd,Web服务器httpd等。
守护进程还有一个特点:其它进程都是在用户登录或运行程序时创建,在运行结束或用户注销时终止,但系统服务进程不受用户登录注销的影响,它们一直在运行着。
我们用ps -axj来查看系统中的进程。-a显示由其他用户所拥有的进程的状态,-x显示没有控制终端的进程,-j显示与作业有关的信息(进程组ID,会话ID,控制终端,终端进程组ID)。守护进程通常以d为结尾。
由上述的进程中,TPGID为-1的都是没有控制终端的进程,也是守护进程。还有像COMMAND那一列中,用[]括起来的进程名,都表示内核线程。这些线程在内核里创建,没有用户空间代码,因此没有程序文件名和命令行,以k开头,表示Kernel。它自成进程组,自成会话。
进程1通常是init,它是一个系统守护进程。
二、创建守护进程
我们写一个mydaemon:
步骤哈:1.创建守护进程首先得,调用umask来将文件模式创建屏蔽字设置为0。
2.调用fork,使父进程退出。因为在这里,后面使用setid不允许进程为进程组id,因此得先将父进程exit。
3.调用setid创建一个新会话,成为会话首进程,成为进程组组长,没有控制终端。这就是守护进程的特点吧。
4.将当前的工作目录改为根目录。你想想,如果你将守护进程的工作目录设置为当前工作目录而非根目录,那么如果将这个目录删除后,就会导致严重的丢失问题。你的那个目录将不能被删除。
5.关闭不再需要的文件描述符。
守护进程实现:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
void mydaemon()
{
umask(0);
if(fork() <= 0)
{}
else
{
exit(0);
}
setsid();
signal(SIGCHLD,SIG_IGN);
close(0);
close(1);
close(2);
chdir("/");
}
int main()
{
mydaemon();
while(1);
return 0;
}
运行结果:
这样一个守护进程就写好啦。当然库里边也实现了一个守护进程,daemon函数。
int daemon(int nochdir, int noclose);
这里nochdir表示不改变当前守护进程的目录,noclose表示不关闭进程文件描述符。
当前我们是把工作目录修改了,所以:
当我们都设置为0时,daemon(0,0);说明修改; 当我们都设置为1时,daemon(1,1);说明不修改;
三、为什么创建守护进程时有人fork两次?
第二次fork的作用:虽然当前关闭了和终端的联系,但是后期可能会误操作打开了终端。只有会话首进程能打开终端设备,也就是再fork一次,再把父进程退出,再次fork的子进程作为守护进程继续运行,保证了该精灵进程不是会话的首进程,第二次不是必须的,是可选的,市面上有些开源项目也是fork一次。(再次fork一次,保证daemon进程,之后不会打开tty设备)