【操作系统】进程组Group|进程会话Session

🔥博客主页: 我要成为C++领域大神
🎥系列专栏【C++核心编程】 【计算机网络】 【Linux编程】 【操作系统】
❤️感谢大家点赞👍收藏⭐评论✍️

本博客致力于知识分享,与更多的人进行学习交流

亲缘关系

Linux操作系统下,进程间的关系是强亲缘(父子),弱亲缘(爷孙)

爷爷进程与孙子进程最低限度亲缘(继承关系)

强亲缘关系(父子进程),子进程被父进程创建,子进程的任务被父进程指定,继承父进程数据,子进程结束后,父进程负责回收避免僵尸问题,整个子进程的生命周期父进程要全程参与。(“中国式家长”

在shell下执行的所有命令创建的进程都是shell的子进程。

我们来验证一下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/fcntl.h>
 

int main()
{
    printf("Child Process PID:%d\n",getpid());
    printf("Parent Process PID:%d\n",getppid());
    while(1){
        sleep(1);
    }
	return 0;
}

getppid即get parent pid,获取父进程的pid

在操作系统中,fork创建进程+execl重载进程是广泛使用

Process Group进程组

一个进程组一般由一个组长和若干组员组成。

终端进程被创建,默认就是进程组的组长进程(系统会分配一个进程组)。

组长进程的唯一标志:组id==进程id

getpid(),返回进程pid
getppid(),返回进程父进程的pid
getpgrp(),返回进程进程组的id

使用这三个函数查看一个进程组之间的关系:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/fcntl.h>
 

int main()
{
    int i;
    pid_t pid;
    for(i=0;i<3;++i){
        pid=fork();
        if(pid==0) break;
    }
    if(pid>0){
    printf("Parent PID:%d,PPID:%d,GroupID:%d\n",getpid(),getppid(),getpgrp());
    }
    else if(pid==0){
    printf("Child PID:%d,PPID:%d,GroupID:%d\n",getpid(),getppid(),getpgrp());
    }else{
        perror("fork call failed");
        exit(0);
    }
	return 0;
}

进程组的销毁:组中最后一个进程,结束或转移,进程组中没有进程时系统会释放进程。

就近原则:子进程被创建后默认归纳到父进程同组的组员

组长是不允许转移的。

组长进程无法创建进程组,组员进程可以创建新组,脱离原有进程组,成为新的组长

子进程成立新组后,亲缘关系不变,子进程依然由父进程回收(子进程脱离原有进程组,父进程可以通过waitpid跨组回收)

setpgid(pid_t pid,pid_t gid)

可以让组员创建新组,也可以将一个组员转移到其他组。

转移时目标组必须存在,需要对目标组有访问权限才可以完成转移

创建:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/fcntl.h>
 

int main()
{
    int i;
    pid_t pid;
    for(i=0;i<3;++i){
        pid=fork();
        if(pid==0) break;
    }
    if(pid>0){
    printf("Parent %d PID:%d,PPID:%d,GroupID:%d\n",i,getpid(),getppid(),getpgrp());
    }
    else if(pid==0){
        if(i==2)//对创建的一个子进程脱离当前组创建一个新的组
        { 
    printf("Child %d PID:%d,PPID:%d,GroupID:%d\n",i,getpid(),getppid(),getpgrp());     
    printf("Child %d PID:%d is Creating Group\n",i,getpid());
    setpgid(getpid(),getpid());
    printf("Child %d PID:%d,GroupID:%d\n",i,getpid(),getpgrp());
             
        }
    printf("Child %d PID:%d,PPID:%d,GroupID:%d\n",i,getpid(),getppid(),getpgrp());
    }else{
        perror("fork call failed");
        exit(0);
    }
	return 0;
}

转移:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main() {
    pid_t pid1, pid2;
    pid_t gpid = -1; // 用于存储新进程组的组ID

    // 创建第一个子进程
    if ((pid1 = fork()) < 0) {
        perror("fork error");
        exit(1);
    } else if (pid1 == 0) {
        // 第一个子进程
        printf("Child 1 PID:%d, PPID:%d, GroupID:%d\n", getpid(), getppid(), getpgrp());

        // 创建新的进程组
        if (setpgid(getpid(), getpid()) < 0) {
            perror("setpgid error for Child 1");
            exit(1);
        }

        printf("Child 1 PID:%d is Creating Group with GroupID:%d\n", getpid(), getpgrp());
        printf("Child 1 PID:%d, GroupID:%d\n", getpid(), getpgrp());

        // 子进程1循环等待
        while (1) {
            sleep(1);
        }
    }

    // 父进程
    printf("Parent PID:%d, GroupID:%d\n", getpid(), getpgrp());

    // 延时等待第一个子进程完成创建新进程组
    sleep(1); // 等待1秒,确保第一个子进程已经执行完setpgid

    // 获取第一个子进程的组ID
    gpid = pid1;

    // 创建第二个子进程
    if ((pid2 = fork()) < 0) {
        perror("fork error");
        exit(1);
    } else if (pid2 == 0) {
        // 第二个子进程
        printf("Child 2 PID:%d, PPID:%d, GroupID:%d\n", getpid(), getppid(), getpgrp());

        // 将第一个子进程移动到新的进程组中
        if (setpgid(getpid(), gpid) < 0) {
            perror("setpgid error for Child 2");
            exit(1);
        }

        printf("Child 2 PID:%d is Changing Group for Child 1\n", getpid());
        printf("Child 2 PID:%d, GroupID:%d\n", getpid(), getpgrp());

        // 子进程2循环等待
        while (1) {
            sleep(1);
        }
    }

    // 父进程等待所有子进程结束
    wait(NULL);
    wait(NULL);

    return 0;
}

Process Session会话关系

会话是一种终端进程管理的组织结构。

在一个终端下创建的一组会话。会话发起者杀死进程是按组杀死的。

关闭终端,在这个会话组创建的其他进程也被杀死了。

如果子进程创建新组了可以存活,但是这个子进程并没有脱离会话。

如果子进程脱离了会话,创建新的会话,也可以存活。(脱离控制终端)

如何脱离控制终端会话?

当一个终端关闭时,那么该终端下创建的其它会话参与者也会被杀死。那么有没有方法避免会话参与者被杀死呢?

1、新建组
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/fcntl.h>
 

int main()
{
    int i;
    pid_t pid;
    for(i=0;i<3;++i){
        pid=fork();
        if(pid==0) break;
    }
    if(pid>0){
    printf("Parent %d PID:%d,PPID:%d,GroupID:%d\n",i,getpid(),getppid(),getpgrp());
    while(1) sleep(1);
    }
    else if(pid==0){
    if(i==1)
    { 
    printf("Child %d PID:%d,PPID:%d,GroupID:%d\n",i,getpid(),getppid(),getpgrp());
    printf("Child %d PID:%d is Creating Group\n",i,getpid());
    setpgid(getpid(),getpid());
    printf("Child %d PID:%d GroupId:%d  SessionID:%d\n",i,getpid(),getpgrp(),getsid(getpid()));
    while(1) sleep(1);
    }
    printf("Child %d PID:%d,PPID:%d,GroupID:%d\n",i,getpid(),getppid(),getpgrp());
    }else{
        perror("fork call failed");
        exit(0);
    }
	return 0;
}

创建了新组的子进程仍然存活。

2、新建会话

使用setsid()函数创建新的会话。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/fcntl.h>
 

int main()
{
    int i;
    pid_t pid;
    for(i=0;i<3;++i){
        pid=fork();
        if(pid==0) break;
    }
    if(pid>0){
    printf("Parent %d PID:%d,PPID:%d,GroupID:%d\n",i,getpid(),getppid(),getpgrp());
    while(1) sleep(1);
    }
    else if(pid==0){
    if(i==1)
    { 
    printf("Child %d PID:%d,PPID:%d,GroupID:%d\n",i,getpid(),getppid(),getpgrp());
    printf("Child %d PID:%d is Changing Sessin\n",i,getpid());
    setsid();
    printf("Child %d PID:%d GroupId:%d  SessionID:%d\n",i,getpid(),getpgrp(),getsid(getpid()));
    while(1) sleep(1);
    }
    printf("Child %d PID:%d,PPID:%d,GroupID:%d\n",i,getpid(),getppid(),getpgrp());
    }else{
        perror("fork call failed");
        exit(0);
    }
	return 0;
}

创建了新会话的进程仍然存活。

  • 15
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值