Answers:
当然!“包装器”程序中的常见模式是先做各种事情,然后仅通过exec
调用(没有派生)将其替换为其他程序。
#!/bin/sh
export BLAH_API_KEY=blub
...
exec /the/thus/wrapped/program "$@"
一个真实的例子是GIT_SSH
(尽管如果您不想执行上述包装程序方法git(1)
,也可以GIT_SSH_COMMAND
这样做)。
仅产生一个典型的工作进程时(例如,Apache httpd
以fork模式使用(虽然仅fork更好地适合需要消耗CPU的进程,而不是那些费力地等待网络I / O的进程)的进程)才使用Fork-only。)或权限分离使用sshd
在OpenBSD(没有exec和其他程序)
$ doas pkg_add pstree
...
$ pstree | grep sshd
|-+= 70995 root /usr/sbin/sshd
| \-+= 28571 root sshd: jhqdoe [priv] (sshd)
| \-+- 14625 jhqdoe sshd: jhqdoe@ttyp6 (sshd)
所述root
的sshd已对客户端连接两岔断(28571)的本身的副本,然后对权限分离另一个副本(14625)。
有很多。
fork()
不带调用的程序exec()
通常遵循一种生成子工作者进程的模式,以在与主进程不同的进程中执行各种任务。你会在程序发现这是改变的dhclient
,php-fpm
和urxvtd
。
exec()
不进行调用的程序fork()
就是链式加载,将其过程覆盖到另一个程序映像中。整个链加载实用程序的亚文化是对进程状态做特定的事情,然后执行另一个程序以修改后的进程状态运行。这些实用程序在daemontools服务和系统管理工具集的家族中很常见,但不仅限于此。一些例子:
chpst
从Gerrit Pape的肖像s6-softlimit
以及s6-envdir
Laurent Bercot的s6local-reaper
并move-to-control-group
从我的NOSH工具集rdprio
而idprio
在FreeBSDnumactl
在FreeBSD和Linux上该家庭daemontools的工具集有很多这样的工具,从machineenv
通过find-matching-jvm
到runtool
。
您要执行此操作的原因至少有两个:
这就是每个守护程序每次启动都要做的事情(实际上是两次)。这可以做几件事,其中shell不会挂起(因为shell等待的原始进程终止),并且守护进程不再由终端控制,因此关闭shell窗口不会杀死该守护进程。
另一个常见的用途是分叉工人的孩子,这是25年前由apache网络服务器而闻名的(如今,由于非常容易出现雷电群问题,现在不再被认为是最新技术,但是它确实提供了尽可能简化最强大的服务器)。
另一个常见用途是创建一致的快照。fork
不仅创建一个进程,它还复制(理论上,实际上它仅标记页面写时复制)地址空间。这(从原子上)创建了完整程序数据的快照,父级无法再对其进行修改。
一些程序利用了这一点。例如,redis将数据保存到磁盘(处于一致状态),同时同时修改数据集。这仅适用,因为fork
创建了一个一致的快照,看不到父进程所做的修改。