《UNIX环境高级编程》(APUE) 笔记第十三章 - 守护进程
13 - 守护进程
1. 守护进程
守护进程 (daemoon) 是生存期长的一种进程。常常在系统引导装入时启动,仅在系统关闭时才终止。它们是在后台运行的,没有控制终端。UNIX 有很多守护进程,它们执行 日常事务活动 。
2. 守护进程的特征
内核进程:父进程 ID 为 \(0\) 的各进程通常是内核进程,它们作为系统引导装入的一部分而启动 。
内核守护进程:对于需要在进程上下文执行工作但却不被用户层进程上下文调用的每一个内核组件,通常有它的内核守护进程 。
init 进程:是一个 系统守护进程 ,主要负责启动各运行层次特定的系统服务 。
用户层守护进程:init 进程启动的系统服务通常是在它们自己拥有的守护进程的帮助下实现的,用户层守护进程的父进程是 init 进程 。
守护进程的特征:
- 大多数守护进程都是以超级用户( root )特权运行
- 所有守护进程都没有控制终端,其控制终端名设置为问号
- 内核守护进程以无控制终端方式启动
- 用户层守护进程缺少控制终端可能是守护进程调用了 setsid 的结果
- 大多数用户层守护进程都是进程组的组长进程以及会话的首进程,而且是这些进程组和会话中的唯一进程
3. 编程规则
编写守护进程程序需遵循一些 基本规则:
- 调用 umask 将文件模式创建屏蔽字设置为一个已知值(通常是 \(0\) )。因为由继承得来的文件模式创建屏蔽字可能会被设置为拒绝某些权限,而如果守护进程要创建文件,那么它可能要设置特定的权限 。
- 调用 fork ,然后使父进程 exit 。这样做有两个原因:
- 如果该守护进程是作为一条 shell 命令启动的,那么父进程终止会让 shell 认为这条命令已经执行完毕,shell 可以执行其他命令,形式上做到了守护进程与终端控制的脱离
- 子进程继承了父进程进程组 ID ,但获得了新的进程 ID,这就保证了子进程不是一个进程组的组长进程(使用 setsid 的先决条件 )
- 调用 setsid 创建一个新会话 。使调用进程:成为新会话首进程、成为一个新进程组的组长进程、没有控制终端。( 在此可再次调用 fork ,终止父进程,继续使用子进程中的守护进程,保证该守护进程不是会话首进程。 )
- 将当前工作目录更改为根目录。因为从父进程继承过来的当前工作目录可能在一个挂载的文件系统中,守护进程随系统存在的特性使得此文件系统不能被卸载。也可以将当前工作目录更改到某个指定位置。
- 关闭文件描述符。
- 某些守护进程打开
/dev/null
使其具有文件描述符 \(0\) 、\(1\) 和 \(2\) ,这样任何一个试图读标准输入、写标准输出或标准错误的库例程都不会产生任何效果。(因为守护进程并不与终端设备相关联)
4. 单实例守护进程
为了正常运作,某些守护进程会实现为:在任一时刻只运行该守护进程的一个副本。例如,这种守护进程可能需要排他地访问一个设备 。
文件和记录锁 机制为一种方法提供了基础,该方法保证一个守护进程只有一个副本在运行 。如果一个守护进程创建一个有固定名字的文件,并在该文件的整体上加一把写锁,那么只允许创建一把这样的写锁,在此之后创建写锁的尝试都会失败,这向后续守护进程副本指明已有一个副本在运行 。