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中vi编辑器的练习心得

    linux中vi编辑器的练习心得

    给大家分享一下在linux中练习vi编辑器的心得以及需要避免的一些坑。
    2017-11-11
  • 在Linux 服务器下修改防火墙允许该端口远程访问的方法

    在Linux 服务器下修改防火墙允许该端口远程访问的方法

    今天小编就为大家分享一篇在Linux 服务器下修改防火墙允许该端口远程访问的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-07-07
  • Kali Linux集群搭建实现过程

    Kali Linux集群搭建实现过程

    这篇文章主要介绍了Kali Linux集群搭建实现过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2026-03-03
  • 使用Apache Spark处理Excel文件的方法

    使用Apache Spark处理Excel文件的方法

    Excel作为功能强大的数据处理软件,广泛应用于各行各业,从企业管理到数据分析,可谓无处不在,本文介绍使用Apache Spark处理Excel文件的简易指南,感兴趣的朋友一起看看吧
    2024-01-01
  • Centos中TCPWrappers访问控制实现

    Centos中TCPWrappers访问控制实现

    这篇文章主要介绍了Centos中TCPWrappers访问控制实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • VPS CentOS-6 下 LNMP HTTP web服务器的搭建步骤

    VPS CentOS-6 下 LNMP HTTP web服务器的搭建步骤

    虽然现在很多朋友比较喜欢使用军哥的lnmp一键安装包,但手工配置方法也要会,否则容易技术退步
    2014-06-06
  • crontab定时任务不执行的原因分析与解决方法

    crontab定时任务不执行的原因分析与解决方法

    这篇文章主要给大家介绍了关于crontab定时任务不执行的原因分析与解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-01-01
  • linux如何将sda分区扩容

    linux如何将sda分区扩容

    这篇文章主要介绍了linux如何将sda分区扩容问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-10-10
  • Centos7.1防火墙开放端口快速方法

    Centos7.1防火墙开放端口快速方法

    这篇文章主要为大家详细介绍了Centos7.1防火墙开放端口的快速方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-01-01
  • Linux Bash脚本自动创建keystore和生成公钥方式

    Linux Bash脚本自动创建keystore和生成公钥方式

    该文章介绍了如何使用Bash脚本自动化生成新的keystore文件并提取公钥的过程,脚本通过获取脚本绝对路径、使用关联数组和函数传递数组参数等方法来实现自动化,并且可以在Windows上使用Git Bash运行
    2025-11-11

最新评论