守护进程是一种运行在后台的特殊进程,它独立于控制终端 ,并周期性地执行某项任务或等待处理某些发生的事件。
守护进程可以由一个普通的进程按照守护进程的特性改造而来。
守护进程创建步骤
- 让程序在后台执行。方法是调用 fork() 产生一个子进程,然后使父进程退出。子进程中进行形式上脱离了控制终端。
- 子进程调用 setsid() 创建一个新会话。控制终端、登录会话和进程组通常是从父进程继承下来的,守护进程要摆脱它们,不受它们的影响,方法是调用 setsid() 使进程成为一个会话组长。setsid() 调用成功后,进程成为新的会话组长和进程组长,并与原来的登录会话、进程组和控制终端脱离。
- 禁止进程重新打开控制终端。经过以上步骤,进程已经成为一个无终端的会话组长,但是它可以重新申请打开一个终端。为了避免这种情况发生,可以通过使进程不再是会话组长来实现。再一次通过 fork() 创建新的子进程,使调用 fork() 的进程退出。
- 关闭不再需要的文件描述符。子进程从父进程继承打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及引起无法预料的错误。首先获得最高文件描述符值,然后用一个循环程序,关闭0到最高文件描述符值的所有文件描述符。
- 使用 chdir() 函数将当前目录更改为根目录。防止占用可卸载的文件系统, 也可以换成其它路径,为了增强程序的健壮性。
- 使用 umask() 函数重设文件权限掩码。子进程从父进程继承的文件创建屏蔽字可能会拒绝某些许可权。为防止这一点,使用 umask()函数 将屏蔽字清零。
- 处理 SIGCHLD 信号。对于服务器进程,在请求到来时往往生成子进程处理请求。如果父进程不等待(wait)子进程结束,子进程将成为僵尸进程(zombie),从而占用系统资源。如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。在 Linux 下可以简单地将 SIGCHLD 信号的操作设为 SIG_IGN。这样子进程结束时不会产生僵尸进程。