当前位置:首页>Linux>Linux守护进程--daemon

Linux守护进程--daemon

  • 2026-09-02 20:32:57
Linux守护进程--daemon
在开始本文前,先补充两个概念
1、进程组组长:进程组的首个进程,除了进程组id = 进程组组长id之外,没什么特权
2、会话id = 进程组id = 会话首进程id
3、父子进程同属于一个进程组
前文我们通过nohup指令 + &创造了一个可以持续在后台运行的进程
但事实上nohup指令还是更侧重于临时测试的时候使用,原因在于此时的进程还没有真正不受会话影响,还不是一个真正意义上的守护进程
nohup只是让进程忽略会话结束时发出的SIGHUP信号,但此时的进程仍是属于当前会话的,仍然会受会话的管理者控制
所以,要想真正创建一个一直运行不受任何影响的进程,你就必须退出当前会话
这个时候就需要介绍一个系统调用接口setsid()
setsid()的作用是创建一个新的会话,并让调用进程成为这个新会话的管理者、新进程组的组长
那么,直接调用setsid()函数就可以了嘛?
我们不妨仔细思考一下
注意调用setsid()后,这个调用进程会变成新会话的管理者,那么如果这个调用进程在调用setsid()函数之前就是一个进程组的组长呢?
那么此时就会出现一个进程是两个进程组的组长的问题,这在Linux中是不允许的
所以在调用setsid()函数之前,我们需要确保当前的进程不是某个进程组的组长
由于父子进程同属于一个进程组,父进程一定先于子进程创建
如果父进程是进程组组长,那么子进程一定不是进程组组长;如果父进程不是进程组组长,说明是父进程的父进程或者更上面是进程组组长,其子进程一定不是进程组组长
所以可以使用当前进程fork()之后的子进程作为我们运行代码的进程
这里提一个细节,父进程通常会等待子进程的退出,也就说父进程在某种程度上管理着子进程,而父进程又在原来的会话里面,原来的会话会影响当前的父进程进而影响你的子进程,所以最好让父进程直接退出,让子进程成为孤儿进程由init接管
id = fork();if (id > 0){    // 父进程    exit(0);}// 子进程setsid();
但是此时还是不够彻底
原因在于此时运行代码的进程是会话的管理者
注意,一个会话是可以不依赖于终端的并且刚开始创建是没有终端的,但是会话的管理者有使用终端的权力
为了防止当前程序误触终端,必须剥夺其权力
但是不能肯定接管的进程不会打开终端,所以最好让当前会话没有管理者,使之永远不可能与终端交互
所以再次使用fork(),以防止进程误触终端,同时让父进程退出使得当前会话没有管理者
// 第一次fork() => 使之不是进程组组长pid_t id = fork();if (id > 0){    // 父进程   => 原来的会话会影响当前的父进程进而影响你的子进程    //            所以最好让父进程直接退出    exit(0);}// 子进程setsid();// 第二次fork() => 使之不是会话管理者id = fork();if (id > 0){    // 父进程   => 使会话没有管理者    exit(0);}// 子进程
此时此刻,一个基本的守护进程(daemon)就完成了
如果你要更改进程的工作目录,可以使用chdir()函数;如果你要设置进程创建文件的mask值,可以使用umask()函数;如果你不使用一些文件描述符,可以使用close()函数关掉
上面的这些操作就完全取决于你的需求了
大家如果有什么感兴趣的内容,欢迎私信或者评论区留言

最新文章

随机文章