【操作系统】进程组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
    评论
由于Linux操作系统是开源的,因此其进程调度算法的代码可以在其代码库中找到。具体来说,Linux使用完全公平调度算法(CFS)作为其默认的进程调度算法,其代码实现可以在内核源代码中的sched目录中找到。以下是一些示例代码: 1. CFS调度器代码: /* * Completely Fair Scheduler * * This file contains the code for the Completely Fair Scheduler, a * process scheduler based on a red-black tree. It implements a * proportional-share scheduling algorithm with low latency for * interactive tasks and high throughput for compute-bound tasks. * * Copyright (C) 2002-2007 Ingo Molnar <mingo@elte.hu> * Copyright (C) 2007-2011 Con Kolivas <kernel@kolivas.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ 2. 调度策略代码: /* Define a scheduling class */ static const struct sched_class fair_sched_class = { .next = &idle_sched_class, .enqueue_task = enqueue_task_fair, .dequeue_task = dequeue_task_fair, .yield_task = yield_task_fair, .check_preempt_curr = check_preempt_wakeup, .pick_next_task = pick_next_task_fair, .put_prev_task = put_prev_task_fair, #ifdef CONFIG_SMP .select_task_rq = select_task_rq_fair, .migrate_task_rq = migrate_task_rq_fair, .task_waking = task_waking_fair, .task_woken = task_woken_fair, #endif .set_curr_task = set_curr_task_fair, .task_tick = task_tick_fair, .task_fork = task_fork_fair, .task_dead = task_dead_fair, #ifdef CONFIG_FAIR_GROUP_SCHED .task_move_group = task_move_group_fair, #endif }; 3. 调度器初始化代码: void __init sched_init(void) { int i; /* Initialize the active and expired arrays for CFS */ for_each_possible_cpu(i) { struct rq *rq = cpu_rq(i); int j; /* Initialize the red-black tree for CFS */ for (j = 0; j < MAX_NICE; j++) { INIT_LIST_HEAD(&rq->cfs_rq[j].tasks); INIT_LIST_HEAD(&rq->cfs_rq[j].runnable); rb_init_node(&rq->cfs_rq[j].rb_node); } rq->cfs_rq[0].exec_clock = rq_clock(rq); rq->cfs_rq[1].exec_clock = rq_clock(rq); rq->cfs_rq[2].exec_clock = rq_clock(rq); rq->cfs_rq[3].exec_clock = rq_clock(rq); rq->cfs_rq[4].exec_clock = rq_clock(rq); rq->cfs_rq[5].exec_clock = rq_clock(rq); rq->cfs_rq[6].exec_clock = rq_clock(rq); rq->cfs_rq[7].exec_clock = rq_clock(rq); rq->cfs_rq[8].exec_clock = rq_clock(rq); rq->cfs_rq[9].exec_clock = rq_clock(rq); rq->cfs_rq[10].exec_clock = rq_clock(rq); rq->cfs_rq[11].exec_clock = rq_clock(rq); rq->cfs_rq[12].exec_clock = rq_clock(rq); rq->cfs_rq[13].exec_clock = rq_clock(rq); rq->cfs_rq[14].exec_clock = rq_clock(rq); rq->cfs_rq[15].exec_clock = rq_clock(rq); rq->nr_running = 0; rq->nr_uninterruptible = 0; rq->curr = NULL; INIT_LIST_HEAD(&rq->migration_queue); INIT_LIST_HEAD(&rq->expired); INIT_LIST_HEAD(&rq->active); rq->expired_timestamp = 0; rq->next_balance = jiffies + HZ; rq->skip_clock_update = 0; rq->idle_stamp = rq_clock(rq); rq->last_moved = jiffies; spin_lock_init(&rq->lock); spin_lock_init(&rq->task_lock); } /* Initialize the idle class */ init_idle(&init_task); init_idle(&ksoftirqd_task); init_idle(&migration_thread); /* Initialize the fair class */ sched_register_scheduler(&fair_sched_class); }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值