博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
写守护进程时, 需要fork两次吗?
阅读量:6260 次
发布时间:2019-06-22

本文共 2732 字,大约阅读时间需要 9 分钟。

glibc源码中我找到了daemon函数的实现:

intdaemon(nochdir, noclose)    int nochdir, noclose;{    int fd;    switch (fork()) {    case -1:        return (-1);    case 0:        break;    default:        _exit(0);    }    if (__setsid() == -1)        return (-1);    if (!nochdir)        (void)__chdir("/");    if (!noclose && (fd = __open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {        (void)__dup2(fd, STDIN_FILENO);        (void)__dup2(fd, STDOUT_FILENO);        (void)__dup2(fd, STDERR_FILENO);        if (fd > 2)            (void)__close (fd);    }    return (0);}

这个把普通进程变成守护进程的函数,很明显只fork了一次. 同样的代码还有nginx:

/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */#include 
#include
ngx_int_tngx_daemon(ngx_log_t *log){ int fd; switch (fork()) { case -1: ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fork() failed"); return NGX_ERROR; case 0: break; default: exit(0); } ngx_pid = ngx_getpid(); if (setsid() == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "setsid() failed"); return NGX_ERROR; } umask(0); fd = open("/dev/null", O_RDWR); if (fd == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "open(\"/dev/null\") failed"); return NGX_ERROR; } if (dup2(fd, STDIN_FILENO) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDIN) failed"); return NGX_ERROR; } if (dup2(fd, STDOUT_FILENO) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDOUT) failed"); return NGX_ERROR; }#if 0 if (dup2(fd, STDERR_FILENO) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDERR) failed"); return NGX_ERROR; }#endif if (fd > STDERR_FILENO) { if (close(fd) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "close() failed"); return NGX_ERROR; } } return NGX_OK;}

也只fork了一次, 那为什么有的文章中却说要fork两次呢?

分析如下:

第一次fork的作用是为setsid服务的, 因为执行setsid的进程不能是session leader, 所以fork一个子进程, 在子进程里进行setsid动作.

而且第一次fork后, 我们已经结束掉了父进程, 子进程已经变成了孤儿进程, 挂靠在init进程下了. 那第二次fork还有必要吗?

那在unix高级环境编程 第13章是这样解释的:

Under System V–based systems, some people recommend calling fork again at this point and having the parent terminate. The second child continues as the daemon. This guarantees that the daemon is not a session leader, which prevents it from acquiring a controlling terminal under the System V rules (Section 9.6). Alternatively, to avoid acquiring a controlling terminal, be sure to specify O_NOCTTY

whenever opening a terminal device.

简单翻译一下:

在基于System V的系统中, 有些人推荐再fork一次, 这些fork产生的进程就不再是session leader了, 避免打开控制终端. 还有一种可选的方法,就是打开终端设备的时候指定O_NOCTTY来避免打开控制终端.

所以在写守护进程时, fork两次并不是必须的.

转载地址:http://sphsa.baihongyu.com/

你可能感兴趣的文章
Mongodb定期备份
查看>>
Confluence 6 数据库设置
查看>>
刨根问底-struts-怎么加载配置的相应的信息
查看>>
解决mysql数据库大小写敏感问题
查看>>
《.NET最佳实践》与Ext JS/Touch的团队开发
查看>>
jsp页面组成
查看>>
LCS记录
查看>>
C++开源跨平台类库集
查看>>
everything搜索工具小技巧
查看>>
一个 Sql语句优化的问题- STATISTICS 统计信息
查看>>
你不知道的KVO的内部实现
查看>>
转】MyEclipse10安装Log4E插件
查看>>
windows server2012r2 安装NET Framework 3.5
查看>>
vss整合配置连接到Myeclipse中以及中文配置
查看>>
[osg][osgEarth][原]基于OE自定义自由飞行漫游器(初级版)
查看>>
Java遇见HTML——JSP篇之JSP基础语法
查看>>
导出一个数据库中的表中的某一条数据
查看>>
JQuery初体验
查看>>
全球顶级黑客对决AI GeekPwn2017黑客大赛看点全面曝光
查看>>
浅析前端开发中的 MVC/MVP/MVVM 模式
查看>>