> 文章列表 > Linux进程层次分析

Linux进程层次分析

Linux进程层次分析

我们知道cgroup(control group)技术是基于进程组的。cgroup是Linux内核提供的一种机制,用于限制、控制和监视进程组的资源使用。通过cgroup,可以将一组进程绑定到一个cgroup中,并对该cgroup中的进程进行资源限制和监视,例如CPU、内存、磁盘I/O等。这样可以避免某些进程占用过多的系统资源,从而提高系统的稳定性和可靠性。

Linux进程组

每一个进程都有一个进程组号(PGID)

  1. 进程组:一个或多个进程的集合(集合中的进程并不孤立)
  2. 进程组中的进程通常存在父子关系,兄弟关系,或者功能相近。

进程组可以方便进程管理(如:同时杀死多个进程,发送一个信号给多个进程)

  1. 每个进程必定属于一个进程组,也只能属于一个进程组
  2. 进程除了有PID外,还有PGID(唯一,但可变)
  3. 每个进程组有一个进程组长,进程组长的PID和PGID相同

进程组相关api

pid_t getpgid(pid_t pid);     // 获取当前进程的组标识

pid_t getpgid(pid_t pid);    // 获取指定进程的组标识

int setpgid(pid_t pid, pid_t pgid);   //设置进程的组标识

        pid == pgid,将pid指定的进程设为组长

        pid == 0,设置当前进程的组标识

        pgid ==0,则将pid作为组标识

默认情况下,子进程与父进程属于同一个进程组

demo1 如下所示:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>int main(int argc,char* argv[]){int pid = 0;int i=0;printf("parent 进程id = %d,ppid 父进程id = %d,pgid 组标识 = %d\\n",getpid(),getppid(),getpgrp());while(i < 5){if((pid = fork()) >0){printf("new: %d\\n",pid);}else if(pid == 0){sleep(1);printf("child = %d,ppid = %d,gpid =%d\\n",getpid(),getppid(),getpgrp());sleep(10);break;}else{printf("fork error...\\n");}i++;}return 0;
}

编译运行输出:

wj@wj:~/WORK/Learning/DT/C++$ gcc pgid_j.c -o pgid_j.out
wj@wj:~/WORK/Learning/DT/C++$ ./pgid_j.out &
[1] 6313
parent 进程id = 6313,ppid 父进程id = 4951,pgid 组标识 = 6313
new: 6315
new: 6316
new: 6317
new: 6318
new: 6319
[1]+  已完成               ./pgid_j.out
wj@wj:~/WORK/Learning/DT/C++$ 
child = 6315,ppid = 1499,gpid =6313
child = 6316,ppid = 1499,gpid =6313
child = 6317,ppid = 1499,gpid =6313
child = 6318,ppid = 1499,gpid =6313
child = 6319,ppid = 1499,gpid =6313
psPID TTY          TIME CMD4951 pts/0    00:00:00 bash6315 pts/0    00:00:00 pgid_j.out6316 pts/0    00:00:00 pgid_j.out6317 pts/0    00:00:00 pgid_j.out6318 pts/0    00:00:00 pgid_j.out6319 pts/0    00:00:00 pgid_j.out6333 pts/0    00:00:00 ps

可以看到当前进程 6313,连续创建了5个子进程,可以看到这5个子进程属于 6313 这个进程组。进程组长是 6313。

问题一:父进程为 6313 ,可是在子进程中的父进程 ppid 却是 1499?这个是怎么回事?

原因:父进程在子进程打印之前就已经结束了,然后子进程全部被收养了。父进程先结束了,那么子进程被初始化进程收养。

现在我们改一下代码,将子进程中第一行代码 sleep(1) 给注释掉。代码如下:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>int main(int argc,char* argv[]){int pid = 0;int i=0;printf("current = %d,ppid = %d,pgid = %d\\n",getpid(),getppid(),getpgrp()); while(i < 5){if((pid = fork()) >0){printf("new: %d\\n",pid);}else if(pid == 0){//sleep(1);printf("child = %d,ppid = %d,pgid =%d\\n",getpid(),getppid(),getpgrp()); // sleep(10);printf("last -- pgid = %d\\n",getpgrp());break;}else{printf("fork error...\\n");}i++;}return 0;
}

再次编译运行,这次输出的结果是正常的。

wj@wj:~/WORK/Learning/DT/C++$ gcc pgid_j.c -o pgid_j.out
wj@wj:~/WORK/Learning/DT/C++$ ./pgid_j.out &
[1] 8484
current = 8484,ppid = 4951,pgid = 8484
new: 8486
new: 8487
child = 8486,ppid = 8484,pgid =8484
new: 8488
child = 8487,ppid = 8484,pgid =8484
new: 8489
child = 8488,ppid = 8484,pgid =8484
new: 8490
child = 8489,ppid = 8484,pgid =8484
child = 8490,ppid = 8484,pgid =8484
[1]+  已完成               ./pgid_j.out
wj@wj:~/WORK/Learning/DT/C++$ last -- pgid = 8484
last -- pgid = 8484
last -- pgid = 8484
last -- pgid = 8484
last -- pgid = 8484