浅墨浓香

想要天亮进城,就得天黑赶路。

导航

第7章 进程关系(3)_进程组和组长进程

Posted on 2017-01-30 23:07  浅墨浓香  阅读(275)  评论(0编辑  收藏  举报

3. 进程组和组长进程

(1)进程组

  ①一个或多个进程的集合;

  ②可以接受同一终端的各种信号,同一个信号发送进程组就等于发送给组中的所有进程

  ③每个进程组有唯一的进程组ID

  ④进程组的消亡要等到组中所有的进程结束

  ⑤kill发送信号组进程组:kill -9 -进程组号注意进程组号前的“-”

(2)组长进程

  ①每个进程组可以有个组长进程,组长进程的ID就是进程组的ID

  ②组长进程可以创建进程组及该组中的进程。

  ③进程组的创建从第一个进程(组长进程)加入开始

  ④进程组的组号取第一个加入组的进程(组长进程)的编号

(3)获取或设置进程组ID

头文件

#include <unistd.h>

函数

pid_t getpgrp(void);  //返回调用进程的进程组ID

pid_t getpgid(pid_t pid); //进程pid所在进程组的ID,出错返回-1

int setpgid(pid_t pid, pid_t pgid); //将进程加入到指定的进程组中,其中pid为进程号,pgid为进程组号。成功返回0,出错返回-1。

功能

获取或设置进程组ID

备注

①getpgid(0)与getpgid(getpid())等价,都是获得当前进程的进程组ID

②第1次调用setpgid,则创建一个进程组,而调用进程成为组长进程。如

setpgid(getpid(), getpid());//第2个参数为进程组ID,也是组长进程。

③②用fork创建一个新进程后子进程默认是和父进程在一个进程组内

【编程实验】1.进程扇与分组

//process_swing_group.c

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{
    pid_t pid;
    int i = 0;

    //创建进程组,组长进程为父进程
    setpgid(getpid(), getpid());
    pid_t group1 = getpgid(getpid()); //获取进程组ID
    pid_t group2;

    //构建进程扇
    for(i = 0; i<3; i++) {
        pid = fork();
        if(pid < 0 ){
            perror("fork error");
            exit(1);
        }else if(pid > 0) { //parent process
            //父进程中执行和子进程相同的操作,因为父、子进程
            //谁先被调用未知,所以设置进程组ID时,需要父子进程同时设置
            //以确保不管谁先运行,都能正确将他们分组
            if(i == 0){
                //将第一个子进程加入到group1中
                setpgid(pid, group1);
            }
            if(i == 1){
                //创建进程组,第二个子进程为组长进程
                setpgid(pid, pid);
                group2 = getpgid(pid);
            }
            if(i == 2){
                //第3个子进程加入到group2中
                setpgid(pid, group2);
            }
            continue; //父进程继续运行,创建新的子进程
        }else{
            if(i == 0){
                //将第一个子进程加入到group1中
                setpgid(getpid(), group1);
            }
            if(i == 1){
                //创建进程组,第二个子进程为组长进程
                setpgid(getpid(), getpid());
                group2 = getpgid(getpid());
            }
            if(i == 2){
                //第3个子进程加入到group2中
                setpgid(getpid(), group2);
            }
            
             break; //要构建进扇,子进程须退出。
        }
    }

    printf("pid = %d, ppid = %d, pgid = %d\n", 
                    getpid(), getppid(), getpgid(0));
    
    for(i=0; i<3; i++)
        wait(0);   
}
/*输出结果:
pid = 3196, ppid = 2447, pgid = 3196
pid = 3198, ppid = 3196, pgid = 3198
pid = 3197, ppid = 3196, pgid = 3196
pid = 3199, ppid = 3196, pgid = 3198
*/

【编程实验】2.进程链与分组

//process_link_group.c

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{
    setpgid(getpid(), getpid());
    pid_t group1 = getpgid(getpid());

    pid_t pid;
    int i = 0;
    //构建进程链
    for(i = 0; i<2; i++) {
        pid = fork();
        if(pid < 0 ){
            perror("fork error");
            exit(1);
        }else if(pid > 0) { //parent process
            if(i == 0){
                //创建进程组2,第1个子进程作为组长进程
                setpgid(pid, pid);
            }
            if(i == 1){
                //将第2个子进程加入到group1
                setpgid(pid, group1);
            }

            break;//在进程链,父进程操作完退出循环
        }else{ //child process
            if(i == 0){
                //创建进程组2,第1个子进程作为组长进程
                setpgid(getpid(), getpid());
            }
            if(i == 1){
                //将第2个子进程加入到group1
                setpgid(getpid(), group1);
            }

            continue; //子进程继续创建新的子进程
        }
    }

    printf("pid = %d, ppid = %d, pgid = %d\n",
                  getpid(), getppid(), getpgid(0));
    
    wait(0);
}
/*
 pid = 3216, ppid = 2447, pgid = 3216
 pid = 3217, ppid = 3216, pgid = 3217
 pid = 3218, ppid = 3217, pgid = 3216
 */

【编程实验】3. 操作进程组

//process_group3.c

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

/*父子进程加入同一进程组*/

//说明:
//(1)默认即使以下代码中不加入setpgid的操作,fork出来的子进程与父进程仍会默认地属一进程组
//(2)kill -9 -进程组ID,则父子进程均会收到退出进程的信号
//(3)如果先kill父进程,则子进程成为孤儿进程,会被1号进程领养
//(4)如果先kill子进程,则子进程成为僵尸进程。如果再kill父进程,则回收僵尸进程。
int main(void)
{
    //创建进程组,父进程作为组长进程
    pid_t pid = fork();
    if(pid < 0){
        perror("fork error");
        exit(1);
    }else if(pid > 0){ //parent process
        //将子进程加入到父进程所在的组
        setpgid(pid, getpgid(getpid()));
    }else{ //child process
        //将子进程加入到父进程所在的组
        setpgid(getpid(), getpgid(getppid()));
    }

    printf("pid = %d, ppid = %d, pgid = %d\n",
                   getpid(), getppid(), getpgid(0));
    pause();//暂停。父子进程都会执行到这里。

    return 0;
}
/*输出结果:
pid = 3301, ppid = 2447, pgid = 3301
pid = 3302, ppid = 3301, pgid = 3301
*/