守护进程也叫精灵进程(daemon):它独立于控制终端,并且周期性的执行某些操作或者等待某个任务,是一种很有用的进程。Linux下的服务器大多是由守护进程实现的,比如说web服务器,Internet服务器等等,守护进程不收终端登录和注销影响,他们是独立的,自成终端。
一、查看守护进程:
用命令 ps axj 查看进程,得到TPGID一列为-1,说明没有控制终端,就是所谓的守护进程。
二、守护进程的几个特点:
1.守护进程自成进程组,自成会话。
2.命名一般以D结尾,不受一般用户注销和登录影响。
3.是孤儿进程,该进程的pid是1,表示它被init领养。
4.守护进程一般实现服务器,不掉线。即使出现故障掉线了,也会立即重启。
三、创建守护进程:
1.创建守护进程的关键是调用setsid()函数来创建一个会话,并且成为会话的leader。
#include<unistd.h>
pid_t setsid(void);
该函数成功返回会话的id,其实也是进程的id。出错时返回-1。注意:调用时,当前进程不允许时进程组leader,否则返回-1。
为了保证当前进程不是进程组的leader,fork()一个进程,此时进程组包含两个进程,分别是子进程和,父进程,父进程是leader。此时在子进程里调用就可以保证当前进程不是进程组leader。
成功调用该函数的结果:
得到一个id这个id是session 的id。
创建了一个进程组,该id也是当前进程组的leader id。
2.创建守护进程:
①.用umask()来将文件模式创建屏蔽字设置为0,因为守护进程也可能创建文件,为使创建的文件不收umask限制。
②.调用fork(),并且使父进程exit()。因为要当前进程不是进程组leader,才能成功,上面讲过。
③.在子进程里调用setpid创建会话。
④当前工作目录修改为根目录。
⑤.关闭相关的文件描述符,0,1,2三个文件描述符。
⑥.忽略的SIGCHLD的信号。
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void Mydaemon()
{
pid_t id;
umask(0);
id=fork();
if(id>0)
{
exit(0);//父进程退出
}
setsid();
chdir("/");
close(0);
close(1);
close(2);
signal(SIGCHLD,SIG_IGN);
}
int main()
{
Mydaemon();
while(1)
sleep(1);
return 0;
}
运行结果:
产生一个守护进程。
系统自带的产生守护的方法:
#include<unistd.h>
int daemon(int nochdir,int noclose);
参数:默认修改目录,默认关闭文件描述符。
#include<unistdh>
#include<stdio.h>
void create_daemon()
{
daemon(0,0);//调用系统方法
}
int main()
{
craete_daemon();
while(1)
sleep(1);
return 0;
}
结果:
又创建了一个守护进程。
问题答疑:为什么有些人会fork()两次再产生守护进程?
这里有个假设,如果父进程fork()一次,产生守护进程,这时父进程没有安全退出,而守护进程还在继续运行。如果守护进程因为某种原因安全或者非安全退出了,这时守护进程不能被init领养,而变为zombie进程。
但是如果fork()两次,父进程fork()出子进程,子进程再fork()出孙子进程去执行创建守护进程。儿子进程立刻退出,守护进程会被init领养,变为孤儿进程,而父进程不管做任何事都与守护进程无关了。所以说,fork()两次的守护进程是进安全的,避免了僵尸进程的出现。