守护进程
通常,执行命令都要在终端执行。产生的进程也于终端相联系,当shell退出时,和这和终端相关联的进程会收到SIGHUP
信号,默认动作是终止进程。守护进程就是一个不依赖终端的进程
进程组
shell启动一个进程,会给该进程创建一个进程组,进程组id就是进程的pid,也可以用setpgrp
函数来加入一个存在的进程组或创建一个进程组,用getpgrp
获取进程组id。
#include <unistd.h>
pid_t getpgrp(void); /* POSIX.1 version */
功能:获取当前进程的进程组ID
参数:无
返回值:总是返回调用者的进程组ID
pid_t getpgid(pid_t pid);
功能:获取指定进程的进程组ID
参数:
pid:进程号,如果pid = 0,那么该函数作用和getpgrp一样
返回值:
成功:进程组ID
失败:-1
int setpgid(pid_t pid, pid_t pgid);
功能:
改变进程默认所属的进程组。通常可用来加入一个现有的进程组或创建一个新进程组。
参数:
将参1对应的进程,加入参2对应的进程组中
返回值:
成功:0
失败:-1
会话
会话是一个或多个进程组的集合。
- 一个会话可以有一个控制终端。这通常是终端设备或伪终端设备;
- 建立与控制终端连接的会话首进程被称为控制进程;
- 一个会话中的几个进程组可被分为一个前台进程组以及一个或多个后台进程组;
- 如果一个会话有一个控制终端,则它有一个前台进程组,其它进程组为后台进程组;
- 如果终端接口检测到断开连接,则将挂断信号发送至控制进程(会话首进程)。
创建会话注意事项
- 调用进程不能是进程组组长,该进程变成新会话首进程(session header)
- 该调用进程是组长进程,则出错返回
- 该进程成为一个新进程组的组长进程
- 需有root权限(ubuntu不需要)
- 新会话丢弃原有的控制终端,该会话没有控制终端
- 建立新会话时,先调用fork, 父进程终止,子进程调用setsid
#include <unistd.h>
pid_t getsid(pid_t pid);
功能:获取进程所属的会话ID
参数:
pid:进程号,pid为0表示查看当前进程session ID
返回值:
成功:返回调用进程的会话ID
失败:-1
#include <unistd.h>
pid_t setsid(void);
功能:
创建一个会话,并以自己的ID设置进程组ID,同时也是新会话的ID。调用了setsid函数的进程,既是新的会长,也是新的组长。
参数:无
返回值:
成功:返回调用进程的会话ID
失败:-1
守护进程模型
-
创建子进程,父进程退出(必须)
- 所有工作在子进程中进行形式上脱离了控制终端
-
在子进程中创建新会话(必须)
- setsid()函数
- 使子进程完全独立出来,脱离控制
-
改变当前目录为根目录(不是必须)
- chdir()函数
- 防止占用可卸载的文件系统
- 也可以换成其它路径
-
重设文件权限掩码(不是必须)
- umask()函数
- 防止继承的文件创建屏蔽字拒绝某些权限
- 增加守护进程灵活性
-
关闭文件描述符(不是必须)
- 继承的打开文件不会用到,浪费系统资源,无法卸载
-
开始执行守护进程核心工作(必须)
守护进程退出处理程序模型