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的解决办法

    这篇文章主要介绍了详解Linux下出现permission denied的解决办法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-02-02
  • 详解Linux中如何安全地抹去磁盘数据

    详解Linux中如何安全地抹去磁盘数据

    离过职的小伙伴都知道,离职的时候需要上交公司电脑,但是电脑里面有许多我们的个人信息,所以我们就需要先把这些信息都删除,确保无法恢复之后才上交,下面我们来看一下在 Linux 中如何安全地抹去磁盘数据吧
    2023-10-10
  • Linux之权限管理解读

    Linux之权限管理解读

    本文介绍了Linux下的超级用户和普通用户以及它们的命令提示符,接着,详细解释了权限的概念、访问者的分类、文件类型与访问权限以及文件权限值的表示方法,最后,文章讨论了文件权限的设置方法,包括chmod、chown和chgrp命令,并列举了一些常见权限问题
    2025-03-03
  • Linux下安装SVN服务端的方法步骤

    Linux下安装SVN服务端的方法步骤

    这篇文章主要介绍了Linux下安装SVN服务端的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • linux中expect的介绍与使用示例

    linux中expect的介绍与使用示例

    expect是一种自动交互语言,能实现在shell脚本中为scp和ssh等自动输入密码自动登录。下面这篇文章主要介绍了linux中使用expect的方法示例,需要的朋友可以参考借鉴,下面来一起学习学习吧。
    2017-01-01
  • Linux系统磁盘格式化以及手动增加swap分区

    Linux系统磁盘格式化以及手动增加swap分区

    本文给大家详细介绍了在Linux系统中磁盘格式化 以及手动增加swap分区的方法和命令,十分全面,有需要的小伙伴可以参考下
    2018-09-09
  • ubuntu mysql更改tmp路径的方法

    ubuntu mysql更改tmp路径的方法

    因为mysql经常要把文件定入tmp目录,而tmp的目录为/tmp,为了提高性能,所以考虑更改tmpdir目录为/run/shm,即使用内存来存储。下文给大家介绍ubuntu mysql更改tmp路径的方法,一起看看吧
    2016-10-10
  • Linux如何永久修改Mysql最大连接数

    Linux如何永久修改Mysql最大连接数

    文章介绍了如何在Linux上永久修改MySQL的最大连接数,包括查找配置文件位置、编辑my.cnf文件、重启服务以及查看连接数,如果修改后连接数没有变化,还提供了解决方案,包括修改mysqld.service文件以增加文件描述符限制
    2024-11-11
  • 详解Linux系统如何防止TCP洪水攻击

    详解Linux系统如何防止TCP洪水攻击

    本篇文章主要介绍了详解Linux系统如何低于TCP洪水攻击,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • LNMP下防跨站、跨目录的安全设置,仅支持PHP5.3.3以上版本

    LNMP下防跨站、跨目录的安全设置,仅支持PHP5.3.3以上版本

    LNMP一键安装包下存在跨站和跨目录的问题,跨站和跨目录影响同服务器/VPS上的其他网站,最近看PHP 5.3,在5.3.3以上已经增加了HOST配置,可以起到防跨站、跨目录的问题
    2012-10-10

最新评论