Linux进程脱离父进程控制设置过程
更新时间:2026年01月29日 11:13:56 作者:学亮编程手记
这篇文章介绍了在Linux系统中使进程完全脱离父进程控制的方法,包括使用`setsid()`、`setpgid()`等系统调用,并推荐使用systemd服务,文中还提到了一些注意事项,如双重fork技巧、信号处理和资源清理等
在Linux中,要使进程完全脱离父进程控制,通常需要使用以下系统调用组合:
1.setsid() - 创建新会话
这是最关键的一步,它会:
- 创建一个新的会话
- 使调用进程成为会话首进程
- 使调用进程成为新进程组的组长
- 使调用进程脱离控制终端
#include <unistd.h>
#include <stdio.h>
int main() {
pid_t pid = fork();
if (pid < 0) {
perror("fork failed");
return 1;
}
// 父进程退出
if (pid > 0) {
_exit(0);
}
// 子进程创建新会话
if (setsid() < 0) {
perror("setsid failed");
return 1;
}
// 此时进程已脱离原会话和控制终端
// 继续执行守护进程逻辑...
return 0;
}
2.setpgid() - 设置进程组ID
用于更精确地控制进程组关系:
#include <unistd.h>
#include <stdio.h>
int main() {
pid_t pid = fork();
if (pid < 0) {
perror("fork failed");
return 1;
}
if (pid == 0) { // 子进程
// 将自己放入新的进程组(通常与setsid配合)
if (setpgid(0, 0) < 0) {
perror("setpgid failed");
return 1;
}
// 然后创建新会话
if (setsid() < 0) {
perror("setsid failed");
return 1;
}
} else { // 父进程
// 父进程可以等待子进程设置完成
sleep(1);
// 父进程退出,子进程被init进程接管
}
return 0;
}
3.完整的守护进程实现
#include <unistd.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
void daemonize() {
pid_t pid;
// 1. 创建子进程,父进程退出
pid = fork();
if (pid < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid > 0) { // 父进程
exit(EXIT_SUCCESS);
}
// 2. 创建新会话,脱离控制终端
if (setsid() < 0) {
perror("setsid");
exit(EXIT_FAILURE);
}
// 3. 改变工作目录到根目录
if (chdir("/") < 0) {
perror("chdir");
exit(EXIT_FAILURE);
}
// 4. 重设文件权限掩码
umask(0);
// 5. 关闭所有文件描述符
for (int i = 0; i < sysconf(_SC_OPEN_MAX); i++) {
close(i);
}
// 6. 重定向标准输入输出到/dev/null
int fd = open("/dev/null", O_RDWR);
if (fd != -1) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (fd > 2) {
close(fd);
}
}
}
int main() {
daemonize();
// 守护进程的主要逻辑
while (1) {
// 执行任务
sleep(10);
}
return 0;
}
4.使用 systemd 服务的现代方法
对于现代Linux系统,推荐使用systemd服务:
# /etc/systemd/system/my-service.service [Unit] Description=My Daemon Service After=network.target [Service] Type=forking PIDFile=/var/run/my-service.pid ExecStart=/usr/local/bin/my-daemon Restart=always User=nobody Group=nogroup # 确保进程完全独立 NoNewPrivileges=yes PrivateTmp=yes ProtectSystem=strict ProtectHome=true PrivateDevices=yes [Install] WantedBy=multi-user.target
5.关键区别
| 系统调用 | 作用 | 效果 |
|---|---|---|
| setsid() | 创建新会话 | 进程成为会话首进程,脱离控制终端 |
| setpgid(pid, pgid) | 设置进程组 | 将指定进程放入指定进程组 |
| fork() + setsid() | 标准守护进程 | 完全脱离父进程控制 |
6.注意事项
- 双重fork技巧:某些情况下需要双重fork确保进程不会成为会话首进程
- 信号处理:重新设置信号处理器,特别是SIGHUP
- 资源清理:关闭不需要的文件描述符
- 工作目录:更改到安全目录,防止占用文件系统
- 日志记录:使用syslog或其他日志机制
这样设置的进程将完全独立于原始父进程,即使父进程退出也不会影响它,并由init/systemd进程接管。
7.总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
相关文章
详解Linux下出现permission denied的解决办法
这篇文章主要介绍了详解Linux下出现permission denied的解决办法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2019-02-02
LNMP下防跨站、跨目录的安全设置,仅支持PHP5.3.3以上版本
LNMP一键安装包下存在跨站和跨目录的问题,跨站和跨目录影响同服务器/VPS上的其他网站,最近看PHP 5.3,在5.3.3以上已经增加了HOST配置,可以起到防跨站、跨目录的问题2012-10-10


最新评论