进程背景本身可以吗?

tom*_*asz 3 linux glibc

进程背景本身可以吗?

什么是 Perl 和/或 C 实现?

Sté*_*las 7

我只想在这里回答字面问题:进程背景本身,而不是 fork 本身,是否可以继续在子进程中执行并退出,以便等待它的进程可以继续执行这里已经被其他人覆盖的进程。

这里首先要注意术语。

后台处理通常是指交互式 shell 中的作业控制。

就像您运行带有&附加的命令一样。或者按Ctrl+Z然后运行bg。

那里的作业不是进程,它们是进程组。当你运行时:

$ ps -ej | grep -w "$$" & echo "$!"
35131
  19152   19152   19152 pts/0    00:00:00 zsh
  35130   35130   19152 pts/0    00:00:00 ps
  35131   35130   19152 pts/0    00:00:00 grep
Run Code Online (Sandbox Code Playgroud)

这是放在后台的ps | grep 工作(这里是通过 35130 进程组实现的,其领导者是正在运行的进程,ps但也包含正在运行的进程grep)。

这里的背景意味着:

  1. shell 不会等待该作业的终止。您将返回到提示,并能够在该作业仍在运行时输入更多命令。
  2. 终端设备驱动程序被告知该进程组不在前台。因此,该进程组的进程没有从终端读取的权利(组中的所有进程将被打断,如果其中的任何进程试图从终端读取)和它不会受到^C/ ^Z/ ^\, 等等。
  3. Shell 在其内部作业表中输入作业并将其记录为当前处于后台。

现在后台措辞有时在终端作业控制之外使用。

当你这样做时:

cmd1 | cmd2 & pid=$!
somecommand
wait
Run Code Online (Sandbox Code Playgroud)

在脚本中,没有作业控制。如果该脚本是通过交互式 shell 在终端中启动的,它本身将被置于前台或后台,具体取决于脚本的启动方式,就像任何其他命令一样。

但是cmd1 | cmd2脚本中的内容不会被解释脚本的外壳程序置于后台,因为它不是交互式外壳程序。

如果按^ C,cmd1并且cmd2将刚杀同旁边运行该脚本的外壳,并暂停当你按下^ Z。与其说cmd1 | cmd2是在后台启动,不如说它们是异步运行的。

与在交互式shell 中在后台启动的作业相比,只完成了1 个。没有创建进程组来运行该管道。

现在,随着这一点的澄清,流程可以将自己置于后台吗?

由于是作业而不是进程置于后台,因此该进程的问题是:

  • 我是否在连接到终端的会话中?(工作控制甚至有意义吗?)
  • 我的进程组中是我一个人还是其他进程?
  • 我的进程组是在前台还是后台?
  • 我的进程组最终是否由交互式 shell 等待?

如果我们可以对所有这些都回答是,也就是说,如果我们从终端中的交互式 shell 作为简单命令(而不是管道或复合命令的一部分)被调用,那么我们需要(1)告诉等待shell 停止等待我们,(2) 告诉终端它的进程组不再是前台进程组,(3) 告诉 shell 更新其作业表以记录我们现在处于后台的事实。

除了终止或挂起之外,您无法真正告诉另一个进程停止等待您,在这种情况下,该进程将收到SIGCHLD信号或wait*()当前正在执行的调用将返回。

但是,您可以通过向自己发送 SIGTSTP 信号(按 时发送的相同^Z)或 SIGSTOP(无法拦截)来暂停自己,在这种情况下,所有 (1)、(2) 和 (3) 都会自动发生,除了作业状态将被暂停而不是在后台运行。

现在,由于您被暂停,您将不再跑步,也无法自行恢复。

但是,您可以分叉一个子进程,该进程将在暂停自己之前的一段时间内恢复自己(通过将 SIGCONT 发送到您的 pid)。

当您恢复执行时,您的 shell 将再次收到一个 SIGCHLD,并且(3)当它开始处理该信号时,shell 将意识到您现在正在后台运行。

举个例子,在sh:

$ sh -c 'echo running in foreground; sleep 1
         (sleep 1; echo resuming my parent; kill -s CONT "$$") &
         echo stopping; kill -s STOP "$$"
         echo resumed
         sleep 30
         echo finished'; echo "$?"
running in foreground
stopping
147
zsh: suspended (signal)  sh -c
$ resuming my parent
resumed
$ jobs
[1]  + running    sh -c
$ finished
[1]  + done       sh -c
Run Code Online (Sandbox Code Playgroud)

也可以使用kill(0, SIGSTOP)( kill -s STOP 0in sh)暂停整个工作,但是进程这样做是否正确,以影响它尚未启动且不知道的进程的运行流程?

sh -c 'echo running in foreground
       perl -MPOSIX -le "setpgid 0,0; # leave the process group before it is suspended
                         sleep 2;
                         print q(resuming the process group of my parent);
                         kill q(CONT), - shift@ARGV
                        " "$(ps -o pgid= -p "$$")" &
       sleep 1
       echo stopping my process group; kill -s STOP 0
       echo process group resumed
       sleep 30
       echo finished' | cat
Run Code Online (Sandbox Code Playgroud)


Jde*_*eBP 5

只是有时。

  • 这是一个过程在后台运行具有处理组ID,它是到当前不同前台进程组ID在其控制终端。
  • 这是不以混淆是一个进程作为守护程序运行,其运行outwith所有登录会话,其中前景和背景的概念根本不适用,因为没有控制摆在首位终端。

Ángel 回答中的建议已过时且糟糕。所谓的“守护进程”在登录会话中并不真正起作用。系统为了建立登录会话而通过的单向活板门太多了;Ángel 的回答不仅忽略了 OpenBSD 的setlogin()、AIX 的受保护环境(请参阅 参考资料setsenv)以及 Linux 的安全上下文和控制组等内容,而且daemon()几乎所有 C 库中的旧库函数也是如此。

它自 1980 年代以来就没有用过;因为 1990 年代引入了许多这种单向活板门。“恶魔化”是一个谬论,不幸的是,这些年来,人们仍然通过接受的智慧和民间传说推广。

这甚至不是守护进程应该做的。1980 年代后期(例如 AT&T Unix 服务访问设施)和 1990 年代(例如 IBM 的系统资源控制器)以后的服务管理子系统调用已经在守护进程上下文中的守护进程。它们首先不是在登录会话上下文中启动的。

此外,fork-and-exit-parent 与服务管理子系统在 30 多年来一直用于守护进程的控制语义发生冲突;关闭文件描述符与服务管理子系统为守护进程设置的日志记录机制冲突。

  • 关闭文件描述符与 TTY 信号无关(这是我之前提到的民间传说的一个例子),并且破坏了从 daemontools 到 systemd 到 runit 的服务管理子系统如何设置标准输出和标准错误以发送到日志。服务管理子系统一开始不会在任意文件描述符打开的情况下启动守护进程;它们以可重复且一致且通常最少(除非明确配置)的一组打开文件描述符开始。
  • 分叉和退出父进程是 1980 年代的事情,当时系统管理员通过将守护进程添加到/etc/rc或/etc/rc.localshell 脚本,甚至从超级用户登录会话中交互地启动守护进程,并破坏了服务管理子系统使用它从fork()ing获得的进程 ID 的事实跟踪和控制服务的服务流程。(正如您从进一步阅读中看到的,IBM 几乎在其系统资源控制器存在的时候就一直建议不要这样做。)服务管理子系统在已经没有控制终端的会话中调用守护进程。

此外,“守护进程”并不是在登录会话的后台执行的操作。“作业控制”shell 通过调用tcsetpgrp()函数来更改控制终端的当前前台进程组 ID值,从而将登录会话中的内容放入前台和后台。这实际上与fork(),chdir()关闭文件描述符或(内核)会话没有任何关系。

shell 的子进程可以调用tcsetpgrp(),但请注意,(a)SIGTTOU如果它已经在后台,它将被发送一个信号,并且 (b) 找到另一个进程组 ID 来切换到,作为 shell 是很重要的在所有情况下可能不是直接父进程。

  • 如果您想在后台启动进程,请使用 shell 的&机制来执行此操作。
  • 如果要交互式地将前台进程组切换到后台,请从终端发送“停止”特殊字符。
  • 如果您想将某些东西作为守护进程运行,与前台和后台无关,那么为您系统的任何服务管理子系统创建一个服务定义。

进一步阅读