守护进程的创建
守护进程的一般概念
守护进程是挂载在后台的,因此其不因远程终端会话的关闭而结束。
并且其往往用于服务器自检和重启动,其应尽可能简洁。
所以我们得到了如下两个特性:
1.后台运行。不受输入输出和控制终端影响
2.与当前环境隔离。包括未关闭的文件描述符、控制终端、会话、进程组、工作目录和文件创建掩码等等
守护进程创建的流程图
graph TB D[远程会话]-->A A[主进程]-.操作一.->B[子进程] B-.操作二.->B[子进程] B-.操作三.->C[孙进程] C-.操作四.->C操作一
创建子进程并杀死主进程。子进程变为孤儿进程由Init进程托管
操作二
setsid函数创建新的会话。子进程会成为新的会话组组长。由于会话过程对终端的独占性,新进程组与控制终端脱离。
操作三
创建孙进程并杀死子进程。孙进程才是真正的守护进程。
操作四
关闭打开的文件描述符
进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及引起无法预料的错误。
代码
int switchDaemon() {
//操作1
pid_t ret = fork();
if (ret == -1) { return -1; }
if (ret > 0) { exit(0); }
//操作2
ret = setsid();
if (ret == -1) { return -2; }
//操作3
ret = fork();
if (ret == -1) { return -3; }
if (ret > 0) { exit(0); }
//操作4
umask(0);
signal(SIGCHLD, SIG_IGN);
}
进程组、进程组组长、前后台进程组、会话之间的关系
graph LR subgraph g1[会话] subgraph g1_1[前台进程组] subgraph g1_1_1[前台进程组组长进程] end subgraph g1_1_2[其他前台进程组进程...] end end subgraph g1_2[后台进程组...] end end如图所示:
- 每个进程组中有多个进程,只有一个进程组组长()
- 一个会话中包含许多进程组,只有一个前台进程组
前台进程组该进程组组长和终端相连,该终端是这个会话的控制终端。
一个会话只能有一个控制终端,而一个控制终端只能控制一个会话。用户通过控制终端,可以向该控制终端所控制的会话中的进程发送键盘信号。
同一会话中只能有一个前台进程组,属于前台进程组的进程可从控制终端获得输入,而其他进程均是后台进程,可能分属于不同的后台进程组。