• 二十七、Linux 进程与信号---进程组和组长进程


    27.1 进程组

    27.1.1 进程组介绍

    • 进程组为一个或多个进程的集合
    • 进程组可以接受同一终端的各种信号,同一个信号发送进程组等于发送给组中的所有进程
    • 每个进程组有唯一的进程组 ID
    • 进程组的消亡要等到组中所有的进程结束
    • 进程组的消亡:kill 发送信号给进程组
      • kill -9  -进程组号

    27.1.2 进程组 ID 获取--- getpgrp 和 getpgid

    (1)getpgrp --- 获取调用进程的进程组ID

    1 #include <unistd.h>
    2 pid_t getpgrp(void);
    • 函数说明
      • getpgrp()用来取得目前进程所属的组识别码。此函数相当于调用 getpgid(0);
    • 返回值
      • 返回目前进程所属的组识别码。

    (2)getpgid --- 获取 pid 所在进程组的 ID  

    1 #include <unistd.h>
    2 pid_t getpgid( pid_t pid);
    • 函数说明
      • getpgid()用来取得参数 pid 指定进程所属的组识别码。如果参数 pid 为0,则会取得目前进程的组识别码。
    • 返回值
      • 执行成功则返回组识别码,如果有错误则返回 -1 ,错误原因存于 errno 中。
    • 错误代码
      • ESRCH 找不到符合参数 pid 指定的进程。
    • getpgid(getpid()) 获取指定进程的进程组
    • getpgid(0) 获取当前进程的进程组

    27.2 组长进程

    27.2.1 概念

    • 每个进程组可以有个组长进程,组长进程的ID就是进程组的ID
    • 组长进程可以创建进程组以及该组中的进程
    • 进程组的创建从第一个进程(组长进程)加入开始
    • 进程组的组号取第一个加入组的进程(组长进程)编号

    27.2.2 设置进程组 ID--- setpgid(创建进程组或将指定进程加入到指定的进程组中)

    1 #include <unistd.h>
    2 int setpgid(pid_t pid,pid_t pgid);
    • 函数说明
      • setpgid() 将参数 pid 指定进程所属的组 ID 设为参数 pgid 指定的组 ID。如果参数 pid 为 0 ,则会用来设置目前进程的组识别码,如果参数 pgid 为0,则会以目前进程的进程 ID 来取代。
    • 函数功能:将进程加入到指定的进程组中, pid 为进程号, pgid 为组号
    • 返回值
      • 执行成功则返回组 ID,如果有错误则返回-1,错误原因存于 errno 中。
    • 错误代码
      • EINVAL 参数 pgid 小于0。
      • EPERM 进程权限不足,无法完成调用。
      • ESRCH 找不到符合参数 pid 指定的进程。

    27.3 例子

    27.3.1 构建进程扇组

      构建一个进程扇,要求每两个进程为一个进程组,如下所示

      

      

     1 #include <unistd.h>
     2 #include <fcntl.h>
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 #include <sys/wait.h>
     6 
     7 int main(void)
     8 {
     9 
    10     //创建进程组,组长进程为父进程
    11     setpgid(getpid(), getpid());
    12 
    13     /* 组1 */
    14     // 或 pid_t group1 = getpgid(0);
    15     pid_t group1 = getpgid(getpid());
    16     pid_t group2;
    17 
    18     int i = 0;
    19     pid_t pid;
    20 
    21     for(; i < 3; i++) {
    22         pid = fork();
    23         if(pid < 0) {
    24             perror("fork error`");
    25             exit(1);
    26         } else if(pid > 0) {//父进程
    27             //父进程中执行和子进程相同的操作
    28             if(i == 0) {
    29                 //要注意fork 在父进程中返回的是子进程的 pid
    30                 setpgid(pid, group1);
    31             }
    32 
    33             //第二个子进程作为组长进程,要创建进程组
    34             if(i == 1) {
    35                 setpgid(pid, pid);
    36                 group2 = getpgid(pid);
    37             }
    38 
    39             if(i == 2) {
    40                 //第三个子进程加入到 group2
    41                 setpgid(pid, group2);
    42             }
    43         } else {//子进程
    44             //将第一个子进程加入到 group1
    45             if(i == 0) {
    46                 setpgid(getpid(), group1);
    47             }
    48 
    49             //第二个子进程作为组长进程,要创建进程组
    50             if(i == 1){
    51                 setpgid(getpid(), getpid());
    52                 group2 = getpgid(getpid());
    53             }
    54 
    55             if(i == 2) {
    56                 setpgid(getpid(), group2);
    57             }
    58 
    59             //因为是进程扇,每一个子进程要退出循环
    60             //父进程继续循环 fork
    61             break;
    62         }
    63     }
    64 
    65     printf("pid: %d, ppid: %d, pgid: %d
    ", getpid(), getppid(), getpgid(0));
    66 
    67     //防止僵尸进程产生
    68     for(i = 0; i < 3; i++) {
    69         wait(0);
    70     }
    71 
    72     exit(0);
    73 }

      编译运行:

      

    27.3.2 构建进程链组

      

     1 #include <unistd.h>
     2 #include <fcntl.h>
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 #include <sys/wait.h>
     6 
     7 int main()
     8 {
     9     //创建进程组1,父进程为组长进程
    10     setpgid(getpid(), getpid());
    11     pid_t group1 = getpgid(getpid());
    12 
    13     pid_t pid;
    14     int i = 0;
    15     for(;i < 2; i++) {
    16         pid = fork();
    17         if(pid < 0) {
    18             perror("fork error");
    19             exit(1);
    20         } else if(pid > 0) {
    21             if(i == 0) {
    22                 //创建进程组2,第一个子进程作为组长进程
    23                 setpgid(pid, pid);
    24             }
    25 
    26             if(i == 1) {
    27                 //将第二个子进程加入到 group1中
    28                 setpgid(pid, group1);
    29             }
    30 
    31             // 在进程链中,父进程操作完退出循环
    32             break;
    33         } else if(pid == 0) {
    34             
    35             if(i == 0) {
    36                 //创建进程组2,第一个子进程作为组长进程
    37                 setpgid(getpid(), getpid());
    38             }
    39 
    40             if(i == 1) {
    41                 //将第二个子进程加入到 group1中
    42                 setpgid(getpid(), group1);
    43             }
    44         }
    45     }
    46 
    47     printf("pid: %d, ppid: %d, pgid: %d
    ", getpid(), getppid(), getpgid(0));
    48 
    49     //防止僵尸进程产生
    50     for(i = 0; i < 2; i++) {
    51         wait(0);
    52     }
    53 
    54     return 0;
    55 }

      编译运行:

      

    27.3.3 进程组删除

     1 #include <unistd.h>
     2 #include <fcntl.h>
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 #include <sys/wait.h>
     6 
     7 int main(void)
     8 {
     9     //创建进程组,父进程作为组长进程
    10     setpgid(getpid(), getpid());
    11 
    12     pid_t pid = fork();
    13     if(pid < 0){
    14         perror("fork error");
    15         exit(1);
    16     } else if(pid > 0) {
    17         //将子进程加入到父进程所在的组
    18         setpgid(pid, getpgid(getpid()));
    19     } else {
    20         //将子进程加入到父进程所在的组
    21         setpgid(getpid(), getpgid(getppid()));
    22     }
    23 
    24     printf("pid: %d, ppid: %d, pgid: %d
    ", getpid(), getppid(), getpgid(0));
    25 
    26     pause();//进程暂停,等待信号
    27 
    28     return 0;
    29 }

      编译运行:

    (1)杀掉进程组

      

      

    (2)杀掉父进程

      

      

      杀掉父进程后,子进程依然存在,只不过变成了孤儿进程,并被2323进程所领养

    (3)杀掉子进程

       

      

      子进程变为了僵尸进程,子进程被杀死,但是父进程并没有回收子进程。

      杀掉父进程:

      

      僵尸进程被回收

    27.3.4 子进程不加入父进程组中

     1 #include <unistd.h>
     2 #include <fcntl.h>
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 #include <sys/wait.h>
     6 
     7 int main(void)
     8 {
     9     //创建进程组,父进程作为组长进程
    10     setpgid(getpid(), getpid());
    11 
    12     pid_t pid = fork();
    13     if(pid < 0){
    14         perror("fork error");
    15         exit(1);
    16     } else if(pid > 0) {
    17         //将子进程加入到父进程所在的组
    18         setpgid(pid, getpgid(getpid()));
    19     } else {
    20         //将子进程加入到父进程所在的组
    21         //setpgid(getpid(), getpgid(getppid()));
    22     }
    23 
    24     printf("pid: %d, ppid: %d, pgid: %d
    ", getpid(), getppid(), getpgid(0));
    25 
    26     pause();//进程暂停,等待信号
    27 
    28     return 0;
    29 }

      编译运行:

      

      

      没有将子进程加入到组中,依然将子进程加入到父进程组了。

      注意:从 shell 上启动一个父进程,然后从父进程上创建若干个子进程,默认情况下都加入到父进程所在的组中,组号就是父进程的 PID,组长就为父进程。

  • 相关阅读:
    AutoMapper在ABP框架
    Github for Windows使用介绍
    Net中的反应式编程
    webstorm创建nodejs + express + jade 的web 项目
    Nancy 框架
    Quartz.NET 任务调度框架
    从电商秒杀与抢购谈Web系统大规模并发
    SVN中tag branch trunk用法详解
    Hsql中In没有1000的限制
    Gradle sourceCompatibility has no effect to subprojects(转)
  • 原文地址:https://www.cnblogs.com/kele-dad/p/9164635.html
Copyright © 2020-2023  润新知