setpgid()函数有什么用途?
严格地说,你的第一个问题的答案是,job id纯粹是一个shell创建.它之所以存在是因为管道(或很少是另一个shell分组构造)可能由多个应该由一个单元控制的进程组成.
为了回答你的上一个问题,shell首先执行fork(2)然后执行execve(2)来启动所有进程.与&的唯一区别是shell不执行wait(2)(或相关变体),因此程序可以“在后台”继续. Unix在前景和背景之间实际上没什么区别.
进程组是由shell定义的关联,以便内核知道处理一组各种“后台”进程的单个“前台”进程.这一点非常重要,因为如果他们决定突然从终端读取,后台进程将产生一个信号. (这样的终端可能连接到标准输入.)这将导致“作业”生成信号,shell将提示用户执行某些操作.
尝试(睡5;读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)打印时会发生一些更微妙的事情.每个终端都知道它的前台进程组是什么,所以我相信一个进程得到一个if pid == pgid&& (pgid是其控制终端的前台pg).
总之,内核保留了几个状态项:pid,pgid,sid,并且进程可以具有控制终端,并且终端可以具有前台pgid.这些凭据主要用于支持作业控制,但也用于在用户注销时撤消对终端的访问.