
2.31、守护进程(2)
- 1.守护进程的创建步骤
- 2.什么情况下子进程不会继承父进程的组ID
- 3.哪些操作会导致子进程的组ID发生改变
- 4.kill怎么杀掉守护进程的
- 实现守护进程
1.守护进程的创建步骤
- 执行一个
fork()
,之后父进程退出,子进程继续执行。 使用子进程的目的是防止创建会话的进程为首进程,创建守护进程(daemon)时,通常需要让该进程摆脱与控制终端的关联,即让它成为一个无终端进程。首进程创建会话会导致新建会话的组id与之前存在的组id相同。
- 子进程调用
setsid()
开启一个新会话。
- 清除进程的
umask
以确保当守护进程创建文件和目录时拥有所需的权限。
- 修改进程的当前工作目录,通常会改为根目录
(/)
。
- 关闭守护进程从其父进程继承而来的所有打开着的文件描述符。
- 在关闭了文件描述符
0、1、2
之后,守护进程通常会打开/dev/null
并使用dup2()
使所有这些描述符指向这个设备。
- 核心业务逻辑
2.什么情况下子进程不会继承父进程的组ID
- 当父进程使用
setpgid()
系统调用将自己加入到一个新的进程组中,而子进程在此之后被创建时,子进程不会继承父进程的PGID
,而是创建一个新的进程组,并将自己作为该进程组的领导进程,PGID
与PID
相同。
- 当父进程在创建子进程之前调用了
setsid()
系统调用创建了一个新的会话,子进程也会在此之后创建一个新的会话,并成为该会话的领导进程,PGID
与PID
相同。
- 当父进程使用
CLONE_NEWPID
或CLONE_NEWUSER
等Linux
特有的命名空间创建了一个新的进程隔离环境时,子进程不会继承父进程的PGID
。
3.哪些操作会导致子进程的组ID发生改变
- 调用
setpgid()
系统调用将子进程加入到一个新的进程组中,子进程的PGID
将被设置为指定的PGID
。
- 在子进程中调用
setpgid()
系统调用将自己加入到一个新的进程组中,子进程的PGID
将被设置为指定的PGID
。
- 在子进程中调用
setsid()
系统调用创建一个新的会话,子进程将成为该会话的领导进程,并且PGID
与PID
相同。
- 在子进程中调用
exec()
系统调用执行另一个程序,新程序的PGID
可能与旧程序不同。
4.kill怎么杀掉守护进程的
- 在
Linux
系统中,kill
命令可以向指定进程发送信号。这个过程是通过进程ID(PID)
来实现的,而不是通过控制终端。即使守护进程没有控制终端,它也有一个PID
,其他进程可以使用这个PID
向它发送信号,其中包括kill
命令发送的信号。
实现守护进程
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <signal.h>
#include <time.h>
#include <fcntl.h>
#include <string.h>void work()
{time_t tm = time(NULL);struct tm* loc = localtime(&tm);char* str = asctime(loc);int fd = open("time.txt", O_CREAT | O_APPEND | O_RDWR, 0664);write(fd, str, strlen(str));}int main()
{pid_t proPid = fork();if (proPid > 0){return 0;}pid_t sePid = setsid();umask(022);chdir("/home/nowcoder/");int fd = open("/dev/null");dup2(fd, STDIN_FILENO);dup2(fd, STDOUT_FILENO);sup2(fd, STDERR_FILENO);struct sigaction act;act.sa_flags = 0;sigemptyset(&act.sa_mask);act.sa_handler = work;sigaction(SIGALRM, &act, NULL);struct itimerval val;val.it_value.tv_sec = 3;val.it_value.tv_usec = 0;val.it_interval.tv_sec = 2;val.it_interval.tv_usec = 0; setitimer(ITIMER_REAL, &val, NULL);while (1){sleep(2);}return 0;
}