守护进程:就是通常说的 Daemon 进程(精灵进程),是 Linux 中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。
其特点是:
1)其父进程是一号进程,通常以d结尾
2)在后台运行,独立于终端,周期性的以某种任务或等待处理某些发生的事
3)自成进程组,自成会话,不受登陆注销等影响
4)一般是孤儿进程
守护进程的创建:
1:调用umask将文件模式屏蔽字设置为0;
2:调用fork()函数,父进程退出;
3:调用setsid创建一个新会话;
4:将当前工作目录更改为根目录;
5:关闭不需要的文件描述符;
6:忽略SIGCHLD信号。
创建守护进程最关键的⼀一步是调⽤用setsid函数创建⼀一个新的Session,并成为Session Leader。
该函数调⽤用成功时返回新创建的Session的id(其实也就是当前进程的id),出错返回-1。注意,调 ⽤用这个函数之前,当前进程不允许是进程组的Leader,否则该函数返回-1。要保证当前进程不 是进 程组的Leader也很容易,只要先fork再调⽤用setsid就⾏行了。fork创建的⼦子进程和⽗父进程在同 ⼀一个进 程组中,进程组的Leader必然是该组的第⼀一个进程,所以⼦子进程不可能是该组的第⼀一个 进程,在⼦子 进程中调⽤用setsid就不会有问题了。
成功调⽤用该函数的结果是:
1. 创建⼀一个新的Session,当前进程成为Session Leader,当前进程的id就是Session的id。
2. 创建⼀一个新的进程组,当前进程成为进程组的Leader,当前进程的id就是进程组的id。
3. 如果当前进程原本有⼀一个控制终端,则它失去这个控制终端,成为⼀一个没有控制终端的进 程。所谓失去控制终端是指,原来的控制终端仍然是打开的,仍然可以读写,但只是⼀一个普 通的打开⽂文件⽽而不是控制终端了。
守护进程的创建的步代码步骤:
1:调用umask将文件模式屏蔽字设置为0;
umask(0);
2:调用fork()函数,父进程退出;
if(fork()<0){}
else if { exit(0);}
3:调用setsid创建一个新会话;
setsid();
4:将当前工作目录更改为根目录;
chdir("/");
5:关闭不需要的文件描述符;
close(1);
close(2);
close(3);
6:忽略SIGCHLD信号。
signal(SIGCHLD_SIG_IGN);
代码实现:
include<sys/stat.h>
6 #include<fcntl.h>
7
8
9 void creat_daemon()
10 {
11 umask(0);
12 pid_t id=fork();
13 if(id<0){
14
15
16 }else if(id!=0){
17 exit(0);
18 }
19 setsid();
20 chdir("/");
21 close(1);
22 close(2);
23 close(3);
24 signal(SIGCHLD,SIG_IGN);
25 }
26
27 int main()
28 {
29 // creat_daemon();
30 daemon(0,0);
31 while(1){
32 // sleep(1);
33 }
34 return 0;
35 }
看看为什么守护进程要fork两次。这里有一个假定,父进程生成守护进程后,还有自己的事要做,它的人生意义并不只是为了生成守护进程。这样,如果父进程fork一次创建了一个守护进程,然后继续做其它事时阻塞了,这时守护进程一直在运行,父进程却没有正常退出。如果守护进程因为正常或非正常原因退出了,就会变成ZOMBIE进程。
如果fork两次呢?父进程先fork出一个儿子进程,儿子进程再fork出孙子进程做为守护进程,然后儿子进程立刻退出,守护进程被init进程接管,这样无论父进程做什么事,无论怎么被阻塞,都与守护进程无关了。所以,fork两次的守护进程很安全,避免了僵尸进程出现的可能性。