daemon 进程为什么要fork两次,与后台运行程序区别?

守护进程(daemon)通过fork两次和setsid确保脱离控制终端,防止信号导致进程退出。第一次fork让shell认为命令结束,第二次fork防止重新打开控制终端。后台程序虽在后台运行,但并未完全脱离终端,会在终端关闭时受到影响。主要区别在于守护进程的独立性和不受终端影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

daemon进程是后台守护进程
daemon函数存在的原因是因为控制终端由于某些原因(如断开终端链接)会发送一些信号的原因。而接收进程处理这些信号缺省动作会让进程退出。这些信号会由于终端上敲一些特殊按键而产生。


int daemon(void)
{
    pid_t pid = fork();
    if( pid != 0 ) exit(0);//parent
    //first children
    if(setsid() == -1)
    {
       printf("setsid failed\n");
       assert(0);
       exit(-1);
    }
    umask(0);
    pid = fork();
    if( pid != 0) exit(0);
    //second children 
    chdir ("/");
    for (int i = 0; i < 3; i++)
    {
        close (i);
    }
    int stdfd = open ("/dev/null", O_RDWR);
    dup2(stdfd, STDOUT_FILENO);
    dup2(stdfd, STDERR_FILENO);
    return 0;
}

  1. 第一次fork 的作用 是让shell 认为本条命令已经终止,不用挂在终端输入上。还有一个作用是为后面setsid服务。setsid的调用者不能让进程组组长(group leader).此时父进程是进程组长。

  2. setsid() 是本函数最重要的一个调用。它完成了daemon函数想要做的大部分事情。调用完整个函数。子进程是会话组长(sid==pid),也是进程组组长(pgid == pid),并且脱离了原来控制终端。到了这一步,基本上不管控制终端如何怎么样。新的进程都不会收到那些信号。

  3. 经过前面2个步骤,基本想要做的都做了。第2次fork不是必须的。也看到很多开源服务没有fork第二次。fork第二次主要目的是。防止进程再次打开一个控制终端。因为打开一个控制终端的前提条件是该进程必须是会话组长。再fork一次,子进程ID != sid(sid是进程父进程的sid)。所以也无法打开新的控制终端。

  4. daemon目的就是防止终端产生的一些信号让进程退出。上面函数并没有直接调用signal函数去处理它。而是间接通过fork和setsid函数使用更少代码优雅处理。而被有些人误以为是僵死进程的原因需要这样处理。

守护进程与用&结尾的后台运行程序有什么区别呢?

最大的区别有几点:
1)守护进程已经完全脱离终端控制台了,而后台程序并未完全脱离终端,在终端未关闭前还是会往终端输出结果
2)守护进程在关闭终端控制台时不会受影响,而后台程序会随用户退出而停止,需要在以nohug xxx & 格式运行才能避免影响
3)守护进程的会话组和当前目录,文件描述符都是独立的。后台运行只是终端进行了一次fork,让程序在后台执行,这些都没改变。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值