51 lines
2.7 KiB
Markdown
51 lines
2.7 KiB
Markdown
# Linux 进程组
|
||
|
||
进程组和会话是为了支持 shell 作业控制而引入的概念。
|
||
|
||
修改进程组 ID 的接口如下:
|
||
|
||
```cpp
|
||
int setpgid(pid_t pid, pid_t pgid);
|
||
```
|
||
|
||
这个函数的含义是,找到进程 ID 为 pid 的进程,将其进程组 ID 修改为 pgid,如果 pid 的值为 0,则表示要修改调用进程的进程组 ID。该接口一般用来创建一个新的进程组。
|
||
|
||
下面三个函数接口含义一致,都是创立新的进程组,并且指定的进程会成为进程组的首进程。
|
||
|
||
如果参数 pid 和 pgid 的值不匹配,那么 setpgid 函数会将一个进程从原来所属的进程组迁移到 pgid 对应的进程组。
|
||
|
||
```cpp
|
||
setpgid(0,0)
|
||
setpgid(getpid(),0)
|
||
setpgid(getpid(),getpid())
|
||
```
|
||
|
||
setpgid 函数有一些限制:
|
||
|
||
1. pid 参数必须指定为调用 setpgid 函数的进程或其子进程,不能随意修改不相关进程的进程组 ID,如果违反这条规则,则返回 -1,并置 errno 为 ESRCH。
|
||
2. pid 参数可以指定调用进程的子进程,但是子进程如果已经执行了exec函数,则不能修改子进程的进程组 ID。如果违反这条规则,则返回-1,并置 errno 为 EACCESS。
|
||
3. 在进程组间移动,调用进程,pid 指定的进程及目标进程组必须在同一个会话之内。这个比较好理解,不加入公司(会话),就无法加入公司下属的部门(进程组),否则就是部门要造反的节奏。如果违反这条规则,则返回-1,并置 errno 为 EPERM。
|
||
4. pid 指定的进程,不能是会话首进程。如果违反这条规则,则返回 -1,并置 errno 为 EPERM。
|
||
|
||
有了创建进程组的接口,新创建的进程组就不必继承父进程的进程组 ID 了。
|
||
|
||
最常见的创建进程组的场景就是在 shell 中执行管道命令。
|
||
|
||
代码如下:
|
||
|
||
```bash
|
||
cmd1 | cmd2 | cmd3
|
||
```
|
||
|
||
下面用一个简单的命令 ps ax|grep nfsd 来说明。
|
||
|
||
ps 进程和 grep 进程都是 bash 创建的子进程,两者通过管道协同完成一项工作,它们隶属于同一个进程组,其中 ps 进程是进程组的组长。
|
||
|
||
进程组的概念并不难理解,可以将人与人之间的关系做类比。一起工作的同事,自然比毫不相干的路人更加亲近。shell 中协同工作的进程属于同一个进程组,就如同协同工作的人属于同一个部门一样。
|
||
|
||
引入了进程组的概念,可以更方便地管理这一组进程了。比如这项工作放弃了,不必向每个进程一一发送信号,可以直接将信号发送给进程组,进程组内的所有进程都会收到该信号。
|
||
|
||
## 外部参考资料
|
||
|
||
1. [一文读懂Linux进程、进程组、会话、僵尸](https://blog.csdn.net/21cnbao/article/details/104489577)
|