Linux——孤儿进程&进程调度&大O(1)调度

目录

孤儿进程

进程优先级

并行和并发的概念

进程的切换

大O(1)调度队列


只有认知的突破 💫才能带来真正的成长 💫编程技术的学习 💫没有捷径 💫一起加油💫

🍁感谢各位的观看 🍁欢迎大家留言 🍁咱们一起加油 🍁努力成为更好的自己🍁

孤儿进程

概念:父进程比子进程先退出,而此时的子进程为孤儿进程。当子进程完成任务后,就会变为僵尸进程,就会有内存泄漏的风险,为了避免这种情况的发生,该孤儿进程会被1号(init/systemd)进程收养。

代码如下所示:

cpp 复制代码
#include <stdio.h> 
#include <unistd.h> 
#include <stdlib.h> 
int main() 
{ 
    pid_t id = fork(); 
    if(id < 0){ 
    perror("fork"); 
    return 1; 
    } 
    else if(id == 0){//child 
    printf("I am child, pid : %d\n", getpid()); 
    sleep(10); 
    }else{//parent 
    printf("I am parent, pid: %d\n", getpid()); 
    sleep(3); 
    exit(0); 
    } 
    return 0; 
}

进程优先级

进程的调度是有优先级之分的,不是随意调度的。输入ps -l指令便可查询更加详细的进程信息。如下所示:

  • UID:代表执行者的身份。

  • PID:代表这个进程的代号。

  • PPID:代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号。

  • PRI:代表这个进程可被执行的优先级,其值越小越早被执行。

  • NI:代表这个进程的 nice 值。它用来调节进程的优先级的。

并行和并发的概念

并发:一个队列对应一个CPU。(第一幅图)

并行:多个调度队列对应着多个CPU。(第二幅图)

如下图所示:

进程的切换

CPU上下文切换:在CPU内部有一套寄存器,这套寄存器存储着当前进程的执行信息(比如,代码执行到哪一步了)当该进程被切换掉的时候,该进程会"打包"自己的执行信息(上下文),给存储在自己的struct task_struct信息块里面,等再次被调度的执行的时候,就会把自己的上下文放在CPU这套寄存器里面,CPU就会接着上次的遗留继续执行。

如下所示的结构和内核代码:

大O(1)调度队列

一个CPU对应着一个调度队列------struct runqueue,其结构如下所示:

解释:

在这个调度队列(struct runqueue)中,有三个部分最重要,分别是:*active*expiredarrays[2]。它们三个的类型都为struct prio_array{int nr_active;int bitmap[5];struct list_head}。*active这个指针指向arrays[0]/arrays[1]里面的内容,被*active指向的部分就是运行部分。*expired反之。queue[140]里面存放的是双链表,这个数组的下标就是对应的优先级,所以优先级相同的进程被纳入到对应的双链表队列中。所以OS就可以以O(1)的复杂度直接遍历这个数组就OK了,对于新建的进程和已经执行完的进程,会按照优先级被纳入到过期队列中,当运行队列里面的所有的进程都执行完后,只需要交换active和expired指针变量里面的值就行了,就可以继续执行了。

整体的结构如下所示:

cpp 复制代码
struct rq { 
    spinlock_t lock; 
    /* 
    * nr_running and cpu_load should be in the same cacheline because 
    * remote CPUs use both these fields when doing load calculation. 
    */ 
    unsigned long nr_running; 
    unsigned long raw_weighted_load; 
    #ifdef CONFIG_SMP 
    unsigned long cpu_load[3]; 
    #endif 
    unsigned long long nr_switches; 
    /* 
    * This is part of a global counter where only the total sum 
    * over all CPUs matters. A task can increase this counter on 
    * one CPU and if it got migrated afterwards it may decrease 
    * it on another CPU. Always updated under the runqueue lock: 
    */ 
    unsigned long nr_uninterruptible; 
    unsigned long expired_timestamp; 
    unsigned long long timestamp_last_tick; 
    struct task_struct *curr, *idle; 
    struct mm_struct *prev_mm; 
    struct prio_array *active, *expired, arrays[2]; 
    int best_expired_prio; 
    atomic_t nr_iowait; 
    #ifdef CONFIG_SMP 
    struct sched_domain *sd; 
    /* For active balancing */ 
    int active_balance; 
    int push_cpu; 
    struct task_struct *migration_thread; 
    struct list_head migration_queue; 
    #endif 
    #ifdef CONFIG_SCHEDSTATS 
    /* latency stats */ 
    struct sched_info rq_sched_info; 
    /* sys_sched_yield() stats */ 
    unsigned long yld_exp_empty; 
    unsigned long yld_act_empty; 
    unsigned long yld_both_empty; 
    unsigned long yld_cnt; 
    /* schedule() stats */ 
    unsigned long sched_switch; 
    unsigned long sched_cnt; 
    unsigned long sched_goidle; 
    /* try_to_wake_up() stats */ 
    unsigned long ttwu_cnt; 
    unsigned long ttwu_local; 
    #endif 
    struct lock_class_key rq_lock_key; 
}; 


//**************************************************************************************//
    /* 
    * These are the runqueue data structures: 
    */ 
struct prio_array { 
    unsigned int nr_active; 
    DECLARE_BITMAP(bitmap, MAX_PRIO+1); /* include 1 bit for delimiter */ 
    struct list_head queue[MAX_PRIO]; 
}; 
相关推荐
HalvmånEver4 小时前
Linux:线程同步
linux·运维·服务器·线程·同步
喵叔哟4 小时前
06-ASPNETCore-WebAPI开发
服务器·后端·c#
Zach_yuan4 小时前
自定义协议:实现网络计算器
linux·服务器·开发语言·网络
岁杪杪4 小时前
关于运维:LINUX 零基础
运维·服务器·php
wdfk_prog4 小时前
[Linux]学习笔记系列 -- [drivers][I2C]I2C
linux·笔记·学习
VekiSon4 小时前
Linux内核驱动——杂项设备驱动与内核模块编译
linux·c语言·arm开发·嵌入式硬件
tianyuanwo4 小时前
企业级NTP客户端配置指南:基于内部NTP服务器的实践
运维·服务器·ntp客户端
Y1rong4 小时前
linux之网络
linux
寄存器漫游者5 小时前
Linux 软件编程 - IO 编程
linux·运维·spring