请告诉我进程组ID和作业ID之间的区别。作业ID是shell程序的内置还是与内核相关?它们各自的用途是什么?当进程在后台运行时,只设置作业ID还是同时设置进程组ID?setpgid()函数的用途是什么?
当进程在后台运行时,内核是否也参与其中,或者由shell负责确定哪个是后台进程,哪个是前台进程?
当进程在后台运行时,内核是否也参与其中,或者由shell负责确定哪个是后台进程,哪个是前台进程?
问题很好。工作ID在大多数情况下只是一个shell构造。内核通过参与作业控制的信号以及内核确定要向哪些进程发送作业控制信号的方式提供支持。
严格来说,对于您的第一个问题,作业ID完全是一个shell创建的。它存在的原因是由于管道(或者很少情况下,其他shell分组结构)可能由多个应当作为一个单元进行控制的进程组成。
回答您的最后一个问题,shell首先通过fork(2)
再进行execve(2)
来启动所有进程。唯一的区别是带有&
的命令不会执行wait(2)
(或其相关变体),因此程序可以继续“在后台”运行。Unix中前台和后台实际上没有太大的区别。
进程组是shell定义的一种关联,使内核知道一个单独的“前台”进程处理一组不同的“后台”进程。这主要是重要的是,这样的后台进程将生成一个信号,如果它们决定突然从终端读取内容时。 (这样的终端可能连接到标准输入。)这将导致“作业”生成信号,而shell将提示用户采取措施。
尝试(sleep 5; read x)&
,并在6秒后输入一个换行或其他东西,以使shell唤醒。这时你会看到类似下面的内容...
[1]+ Stopped ( sleep 5; read x )
...然后您可以键入fg
将其拉到前台。
最初,Unix具有管道和&
,但没有办法在前台和后台之间移动命令或管道,也没有办法帮助突然决定读取标准输入的后台进程。
作业控制及其内核支持是由Bill Joy和其他人在早期版本的BSD和csh(1)中添加的。这些被商业Unix和为工作类似的Linux内核克隆了一行一行。
ps(1)
的问题...
为了支持 shell 的作业控制,内核进程状态包括进程组 ID 和会话 ID。一个 进程组 和一个 作业 是同一回事,但是一个 作业号 只是 shell 捏造的一个标识。如果会话 ID 和 pid 相同,则进程是会话领导者;如果 pgid 和 pid 相同,则进程是进程组领导者。我认为 ps(1)
打印的 +
存在一些微妙的问题。每个终端都知道它的前台进程组是什么,所以我相信,如果 pid == pgid && (pgid 是其控制终端的前台进程组),则进程会得到一个 +。