【发布时间】:2009-10-02 09:11:36
【问题描述】:
请告诉我进程组 ID 和作业 ID 之间的区别。 jobid 是 shell 程序的内置函数还是与内核有关?它们各自的用途是什么?当一个进程在后台运行时,是只设置了jobid还是设置了pgid? setpgid() 函数有什么用?
当一个进程在后台运行时,内核是否也参与了,还是shell负责处理哪个是后台或前台?
【问题讨论】:
请告诉我进程组 ID 和作业 ID 之间的区别。 jobid 是 shell 程序的内置函数还是与内核有关?它们各自的用途是什么?当一个进程在后台运行时,是只设置了jobid还是设置了pgid? setpgid() 函数有什么用?
当一个进程在后台运行时,内核是否也参与了,还是shell负责处理哪个是后台或前台?
【问题讨论】:
好问题。作业 id 主要只是一个 shell 结构。内核以参与作业控制的信号的形式提供支持,以及内核确切知道将作业控制信号发送到哪些进程的方式。
严格来说,第一个问题的答案是,job id 纯粹是一个 shell 创建。它的存在是因为管道(或很少是另一个 shell 分组结构)可能包含多个应作为一个单元进行控制的进程。
要回答您的最后一个问题,shell 通过首先执行 fork(2) 然后执行 execve(2) 来启动所有进程。与& 的唯一区别是shell 不执行wait(2)(或相关变体),因此程序可以“在后台”继续。在 Unix 中,前台和后台实际上几乎没有区别。
进程组是由 shell 定义的关联,以便内核知道处理一组不同“后台”进程的单个“前台”进程。这很重要,以便后台进程在决定突然从终端读取时生成信号。 (这样的终端可能连接到标准输入。)这将导致“工作”产生一个信号,shell 将提示用户做某事。
尝试(sleep 5; read x)& 并在 6 秒后键入 return 或其他内容,以便 shell 唤醒。那时你会看到类似...
[1]+ 已停止(睡眠 5;读取 x)
...然后您输入fg 将其拉到前台。
最初,Unix 有管道,它有 &,但无法在前台和后台之间移动命令或管道,也无法帮助突然决定读取标准输入的后台进程。
Bill Joy 和其他人在 BSD 和 csh(1) 的早期版本中添加了作业控制及其内核支持。这些是由商业 Unix 逐行提取的,并被克隆用于类似工作的 Linux 内核。
关于进程组和ps(1)的问题...
为了支持 shell 中的作业控制,内核进程状态包括进程组 ID 和会话 ID。 进程组和job是一回事,但job number只是shell组成的句柄。如果会话 ID 与 pid 相同,则进程是会话领导者,如果 pgid 与 pid 相同,则进程是进程组领导。我相信ps(1) 打印的+ 正在发生一些更微妙的事情。每个终端都知道它的前台进程组是什么,所以我相信如果 pid == pgid && (pgid 是其控制终端的前台 pg),一个进程会得到一个 +。
总而言之,内核保留了几个状态项:pid、pgid、sid,并且一个进程可能有一个控制终端,一个终端可能有一个前台 pgid。这些凭据主要用于支持作业控制,但也用于在用户注销时撤销对终端的访问。
【讨论】: