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 
#include 
#include 
#include 
#include 

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
ps
    PID TTY          TIME CMD
   4951 pts/0    00:00:00 bash
   6315 pts/0    00:00:00 pgid_j.out
   6316 pts/0    00:00:00 pgid_j.out
   6317 pts/0    00:00:00 pgid_j.out
   6318 pts/0    00:00:00 pgid_j.out
   6319 pts/0    00:00:00 pgid_j.out
   6333 pts/0    00:00:00 ps

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

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

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

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

#include 
#include 
#include 
#include 
#include 

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

深入理解进程组

进程组长终止,进程组依然存在(进程组长仅用于创建新进程组)

父进程创建子进程后立即通过setpgid()改变其组标识(PGID)

同时,子进程也需要通过setpgid()改变自身组标识(PGID)

子进程调用exec()

        父进程无法通过setpgid()改变其组标识(PGID)

        只能自身通过setpgid()改变其组标识(PGID)

//未完待续...

你可能感兴趣的:(#,Linux,系统/文件编程,linux,系统编程)