Pra*_*ota 162
我试图理解双叉,并在这里偶然发现了这个问题.经过大量的研究,这才是我想到的.希望它能帮助那些有同样问题的人更好地澄清事情.
在Unix中,每个进程都属于一个组,而该组又属于一个会话.这是层次结构......
会话(SID)→进程组(PGID)→进程(PID)
流程组中的第一个流程成为流程组负责人,会话中的第一个流程成为会话负责人.每个会话都可以有一个与之关联的TTY.只有会话负责人才能控制TTY.对于一个真正守护进程(在后台运行)的进程,我们应该确保会话负责人被杀死,这样会话就不可能控制TTY.
我在我的Ubuntu上从这个站点运行了Sander Marechal的python示例守护程序.以下是我的评论结果.
1. `Parent` = PID: 28084, PGID: 28084, SID: 28046
2. `Fork#1` = PID: 28085, PGID: 28084, SID: 28046
3. `Decouple#1`= PID: 28085, PGID: 28085, SID: 28085
4. `Fork#2` = PID: 28086, PGID: 28085, SID: 28085
Run Code Online (Sandbox Code Playgroud)
请注意,该过程是之后的会话领导者Decouple#1
,因为它是PID = SID
.它仍然可以控制TTY.
请注意,Fork#2
它不再是会话领导者PID != SID
.此过程永远无法控制TTY.真正守护进来.
我个人觉得术语分叉两次令人困惑.一个更好的习语可能是fork-decouple-fork.
其他感兴趣的链接:
Dan*_*ing 106
严格来说,双叉与将守护进程重新作为子进程无关init
.重新生成孩子所需要的只是父母必须退出.这可以只使用一个fork来完成.另外,单独执行双分叉并不会将守护进程重新为父进程init
; 守护进程的父进程必须退出.换句话说,在分配正确的守护进程时父进程总是退出,以便守护进程重新成为父进程init
.
那么为什么双叉呢?POSIX.1-2008第11.1.3节" 控制终端 "有答案(重点补充):
会话的控制终端由会话领导者以实现定义的方式分配.如果会话负责人没有控制终端,并且在不使用O_NOCTTY选项的情况下打开尚未与会话关联的终端设备文件(请参阅open()),则实现定义终端是否成为会话的控制终端领导.如果不是会话负责人的进程打开终端文件,或者在open()上使用O_NOCTTY选项,则该终端不应成为调用进程的控制终端.
这告诉我们,如果一个守护进程做了这样的事情......
int fd = open("/dev/console", O_RDWR);
Run Code Online (Sandbox Code Playgroud)
...然后守护进程可能获取O_NOCTTY
作为其控制终端,具体取决于守护进程是否是会话负责人,并取决于系统实现.如果程序首先确保它不是会话领导者,则程序可以保证上述呼叫不会获得控制终端.
通常,在启动守护程序时,open()
会调用(从调用后的子进程O_NOCTTY
)将守护程序与其控制终端分离.但是,调用open()
也意味着调用进程将是新会话的会话负责人,这使守护进程可能重新获取控制终端.双叉技术确保守护进程不是会话负责人,然后保证调用/dev/console
,如上例所示,不会导致守护进程重新获取控制终端.
双叉技术有点偏执.如果您知道守护程序永远不会打开终端设备文件,则可能没有必要.此外,在某些系统上,即使守护程序确实打开了终端设备文件,也可能没有必要,因为该行为是实现定义的.但是,没有实现定义的一件事是只有会话负责人才能分配控制终端.如果进程不是会话负责人,则无法分配控制终端.因此,如果你想要偏执并确定守护进程不会无意中获得控制终端,无论任何实现定义的细节,那么双叉技术是必不可少的.
Bea*_*ano 101
查看问题中引用的代码,理由是:
__PRE__
因此,确保将守护进程重新设置为init(以防止守护进程长时间运行),并消除守护进程重新获取控制tty的任何可能性.因此,如果这两种情况都不适用,那么一个分叉就足够了." Unix网络编程 - 史蒂文斯 "有一个很好的部分.
Ste*_*erg 11
取自坏CTK:
"在Unix的某些版本中,你被迫在启动时进行双分叉,以便进入守护进程模式.这是因为单个分叉不能保证从控制终端分离."
归档时间: |
|
查看次数: |
50619 次 |
最近记录: |