您的位置:首页 > 运维架构 > Linux

linux 守护进程

2012-05-03 19:42 141 查看
重点是要理解linux的终端和会话机制。

fork()将终端交给子进程,然后主进程退出,setsid()使子进程成为sessionleader。

改变文件符号。

ps axj
命令查看系统中的进程。参数
a
表示不仅列当前用户的进程,也列出所有其他用户的进程,参数
x
表示不仅列有控制终端的进程,也列出所有无控制终端的进程,参数
j
表示列出与作业控制相关的信息。

凡是
TPGID
一栏写着-1的都是没有控制终端的进程,也就是守护进程。在
COMMAND
一列用
[]
括起来的名字表示内核线程,这些线程在内核里创建,没有用户空间代码,因此没有程序文件名和命令行,通常采用以
k
开头的名字,表示Kernel。
init
进程我们已经很熟悉了,
udevd
负责维护
/dev
目录下的设备文件,
acpid
负责电源管理,
syslogd
负责维护
/var/log
下的日志文件,可以看出,守护进程通常采用以
d
结尾的名字,表示Daemon。
创建守护进程最关键的一步是调用
setsid
函数创建一个新的Session,并成为Session Leader。
该函数调用成功时返回新创建的Session的id(其实也就是当前进程的id),出错返回-1。注意,调用这个函数之前,当前进程不允许是进程组的Leader,否则该函数返回-1。要保证当前进程不是进程组的Leader也很容易,只要先
fork
再调用
setsid
就行了。
fork
创建的子进程和父进程在同一个进程组中,进程组的Leader必然是该组的第一个进程,所以子进程不可能是该组的第一个进程,在子进程中调用
setsid
就不会有问题了。

成功调用该函数的结果是:

创建一个新的Session,当前进程成为Session Leader,当前进程的id就是Session的id。

创建一个新的进程组,当前进程成为进程组的Leader,当前进程的id就是进程组的id。

如果当前进程原本有一个控制终端,则它失去这个控制终端,成为一个没有控制终端的进程。所谓失去控制终端是指,原来的控制终端仍然是打开的,仍然可以读写,但只是一个普通的打开文件而不是控制终端了。

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>

void daemonize(void)
{
pid_t  pid;

/*
* Become a session leader to lose controlling TTY.
*/
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
} else if (pid != 0) /* parent */
exit(0);
setsid();

/*
* Change the current working directory to the root.
*/
if (chdir("/") < 0) {
perror("chdir");
exit(1);
}

/*
* Attach file descriptors 0, 1, and 2 to /dev/null.
*/
close(0);
open("/dev/null", O_RDWR);
dup2(0, 1);
dup2(0, 2);
}

int main(void)
{
daemonize();
while(1);
}


为了确保调用
setsid
的进程不是进程组的Leader,首先
fork
出一个子进程,父进程退出,然后子进程调用
setsid
创建新的Session,成为守护进程。按照守护进程的惯例,通常将当前工作目录切换到根目录,将文件描述符0、1、2重定向到
/dev/null
。Linux也提供了一个库函数
daemon(3)
实现我们的
daemonize
函数的功能,它带两个参数指示要不要切换工作目录到根目录,以及要不要把文件描述符0、1、2重定向到
/dev/null


运行这个程序,它变成一个守护进程,不再和当前终端关联。用
ps
命令看不到,必须运行带
x
参数的
ps
命令才能看到。另外还可以看到,用户关闭终端窗口或注销也不会影响守护进程的运行。

参考:http://learn.akae.cn/media/ch34s03.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: