下面简述一些基本概念,以及对内核代码做最初步的了解;

一 Linux内核进程管理基础

Linux 内核使用 task_struct 数据结构来关联所有与进程有关的数据和结构,Linux 内核所有涉及到进程和程序的所有算法都是围绕该数据结构建立的,是内核中最重要的数据结构之一。
    该数据结构在内核文件 include/linux/sched.h 中定义,是个很大的结构体;在 3.8 的内核中,该数据结构有 380 行。

Linux中进程ID有如下类型:PID,TGID,PGID,SID;
    如果考虑进程之间有复杂的关系,如线程组、进程组、会话组,这些组均有组ID;分别为 TGID、PGID、SID;

内核中使用下面两个函数来实现分配和回收PID:
    static int alloc_pidmap(struct pid_namespace *pid_ns);
    static void free_pidmap(struct upid *upid);

Linux中增加命名空间这个概念是为了虚拟化和方便管理。
    进程命名空间;作用:linux通过命名空间管理进程号,在不同的namespace中可以有pid相同的进程;进程命名空间是一个父子结构,子空间对于父空间可见。

二 task_struct结构

Linux用task_struct结构表示进程,2.6内核的task_struct结构相对于2.4内核有很大变化。
    该结构记录了进程的重要信息。

与进程调度有关的信息包括:

1 state

进程状态;一个进程共有7种可能状态,分别是:TASK_RUNNING、TASK_INTERRUPTIBLE、TASK_UNINTERRUPTIBLE、TASK_STOPPED、TASK_TRACED、EXIT_ZOMBIE和EXIT_DEAD;

2 timestamp

进程发生调度事件的时间(单位是 nanosecond)。

3 prio, static_prio

进程的优先级和静态优先级。Prio表示进程的动态优先级,与2.4内核中goodness()的计算结果相当。在0~MAX_PRIO-1之间取值(MAX_PRIO 定义为 140),其中0~MAX_RT_PRIO-1(MAX_RT_PRIO定义为100)属于实时进程范围,MAX_RT_PRIO~MX_PRIO-1属于非实时进程。数值越大,表示进程优先级越小。static_prio表示进程的静态优先级,相当于2.4内核中的nice。一个进程的初始时间片的大小完全取决于它的静态优先级。

4 sleep_avg

进程的平均等待时间,在0到NS_MAX_SLEEP_AVG之间取值,初值为0,相当于进程等待时间与运行时间的差值。它是动态优先级计算的关键因子,sleep_avg越大,计算出来的进程优先级也越高。

5 interactive_credit

该变量表示进程的交互程度。在-CREDIT_LIMIT到CREDIT_LIMIT+1之间取值,初始值为0,而后根据不同的条件加1减1,一旦该值超过CREDIT_LIMIT,即表示该进程是交互进程。

6 array

指向当前CPU的active就绪进程队列。

7 run_list

进程通过这个list_head变量连接自己到prio_array数组中queue队列,这样相同优先级的进程连接成一个双向列表,表头为prio_array结构中的queue变量。

三 进程运行队列(就绪队列)

Linux内核定义了一个list_head数据结构,字段head和prev分别表示通用的双向链表向前和向后的指针元素。每个task_struct包含一个list_head类型的run_list字段。

在Linux2.4内核中,就绪进程队列是一个全局数据结构,所有的处理器共享同一个队列。调度器对它的所有操作都会因全局自旋锁而导致系统各个处理机之间的等待,使得就绪队列成为一个明显的瓶颈。2.6内核重新设计就绪进程队列为每CPU的数据结构,每个处理器都维护一个自己的就绪队列,这样就避免了2.4内核中的SMP性能瓶颈。

每个CPU的就绪进程队列由一个struct runqueue结构描述,其中最关键的子结构是优先级就绪数组。

描述优先级就绪数组的数据结构是prio_array_t。

四 进程等待队列

Linux等待队列在内核中有很多用途,尤其在中断处理、进程同步以及定时。例如等待一个磁盘操作的终止,等待释放资源,或等待时间经过的固定的时间间隔。

等待队列由双向链表实现。

struct __wait_queue_head {

spinlock_t lock;

struct list_head task_list;

};  //等待队列的头结点

typedef struct__wait_queue_head wait_queue_head_t;

struct __wait_queue {

unsigned int flags; //标识是互斥进程还是非互斥进程

#define WQ_FLAG_EXCLUSIVE      0x01  /* 表示等待进程想要被独占地唤醒  */

void *private;  /* 指向等待进程的task_struct实例 */          
        wait_queue_func_t func;      /* 用于唤醒等待进程      */          
       sruct list_head task_list;  /* 用于链表元素,将wait_queue_t链接到wait_queue_head_t */

};

typedef struct__wait_queue wait_queue_t;

五 进程切换

内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程执行。这种行为称为进程切换、任务切换或上下文切换。
    尽管每个进程都拥有属于自己的地址空间,但所有进程必须共享CPU寄存器。在恢复一个进程的执行之前,内核必须确保每个寄存器装了挂起进程时的值。
    进程恢复前必须装入寄存器的一组数据称为硬件上下文,它的一部分存在TSS段,而剩余部分存放在内核态堆栈中。

每个进程描述符包含一个类型thread_struct的thread字段,来保存进程切换时的硬件上下文。

进程切换主要有两大步:1、切换全局页表项;2、切换内核堆栈和硬件上下文。这个切换工作由context_switch()完成。其中switch_mm完成第一步,而switch_to和__switch_to()主要完成第二步。更详细的,__switch_to()主要完成硬件上下文切换,switch_to主要完成内核堆栈切换。

schedule() --> context_switch() --> switch_to --> __switch_to()

六 进程调度

进程调度由schedule()函数实现。

Linux的进程调度是基于分时技术(time-sharing)。允许多个进程“并发”运行就意味着CPU 的时间被粗略地分成“片”,给每个可运行进程分配一片。

调度策略也是基于依照优先级排队的进程。
在Linux 中,进程的优先级是动态的。调度程序跟踪进程做了些什么,并周期性地调整它们的优先级。在这种方式下,在较长的时间间隔内没有使用CPU的进程,通过动态地增加它们的优先级来提升它们。相应地,对于已经在CPU上运行了较长时间的进程,通过减少它们的优先级来处罚它们。每个进程在创建之初有一个基本的优先级,执行期间调度系统会动态调整它的优先级,交互性高的任务会获得一个高的动态优先级,而交互性低的任务获得一个低的动态优先级。

Linux操作系统支持多进程,进程控制块PCB(Process ControlBlock)是系统中最为重要的数据结构之一。用来存放进程所必需的各种信息,PCB用结构task_struct来表示,包括进程的类型、进程状态、优先级、时钟信息等。

Linux系统中,进程调度操作由schedule()函数执行,这是一个只在内核态运行的函数,函数代码为所有进程共享。

更多详情自行参阅如下;
https://www.cnblogs.com/hazir/p/linux_kernel_pid.html
https://blog.csdn.net/sdulibh/article/details/50827911
https://www.jianshu.com/p/c1c5e347d64c
https://blog.csdn.net/lsjseu/article/details/9249665

Linux内核进程管理基本概念-进程、运行队列、等待队列、进程切换、进程调度相关推荐

  1. Linux内核进程管理专题报告

    一.引言 在Linux内核的五大组成部分(进程管理.内存管理.设备驱动.文件系统.网络协议)中,进程管理是非常重要的一部分,它虽然不像内存管理.虚拟文件系统那样复杂,也不像进程间通信那样条理化,但作为 ...

  2. centos中如何找出系统中 load 高时处于运行队列的进程

    如何用脚本统计出来处于运行队列的进程呢? #1.查看进程的状态 如何把这个脚本在centos创建并运行呢? vi cpustatus.sh 然后把脚本内容复制上去,每隔 1s 统计一次: #!/bin ...

  3. (C++)wchar_t 转 string / TCHAR转为char/判断是否进程运行/获得目标进程的入口

    首先是wchar_t转string void Wchar_tToString(string& szDst, wchar_t* wchar) {wchar_t* wText = wchar;DW ...

  4. Qt一个进程运行另一个进程

    Qt 进程间通信 1. 一个进程运行另一个进程 2. 例程代码 1. 一个进程运行另一个进程 Qt 的 QProcess 类用来启动一个外部程序并与其进行通信. 使用 start() 函数运行一个进程 ...

  5. linux进程运行队列,Linux进程调度中队列的使用

    Linux内核中大量使用了队列,这里仅列举它在进程调度中的几处应用.Linux内核中的队列是以双链表的形式连接起来的,include/linux/list.h中定义了队列并提供了一些接口,详细的介绍可 ...

  6. Linux 内核进程管理之进程ID

    Linux 内核使用 task_struct 数据结构来关联所有与进程有关的数据和结构,Linux 内核所有涉及到进程和程序的所有算法都是围绕该数据结构建立的,是内核中最重要的数据结构之一.该数据结构 ...

  7. 陈老师Linux内核进程管理导学

    <Linux内核分析与应用>第三章 : 进程管理 你认识进程么,就相当于问你认识自己一样难于回答,因为进程每一瞬间都是变化的,就像你的思想无时无刻不在变化一样,因此,本章对进程的讲解可以说 ...

  8. linux xen 管理,ARM平台上运行Xen 可同时管理linux和VxWorks

    Xen项目管理程序从上个世纪90年代就已经在剑桥大学里开始进行,到了2002年项目开源.如今它是最流行的开源管理程序之一,可以在云计算上使用,Xilinx和DornerWorks将这种虚拟化平台应用在 ...

  9. Linux内核进程管理实时调度与SMP

    一,实时调度器类 实时调度类有两类进程: 循环进程SCHED_RR:循环进程有时间片,随着进程的运行时间会减少.当时间片用完时又将其置为初值,并将进程置于队列末尾.先进先出SCHED_FIFO:没有时 ...

最新文章

  1. IOS开发基础知识--碎片45
  2. 派生类构造函数和析构函数的执行顺序
  3. docker运行mywebsql
  4. python基础——迭代器与生成器
  5. vector的实现原理
  6. mysql 换行_教你如何用Python 连接 MySQL
  7. w7下如何安装linux双系统,ubuntu安装教程(下): 教你装win7+Ubuntu双系统
  8. mysql 5.6.20 优化_mysql 5.6.20 占用内存超大,大概400M左右
  9. [linux]关于deepin截图软件在KDE桌面下无法使用粘贴的解决方法
  10. composer 安装
  11. 83页XX市高速智慧公路总体建设方案
  12. bootstrap必填红心_bootstrap如何设置表单必填
  13. Java实现 LeetCode 34 在排序数组中查找元素的第一个和最后一个位置
  14. 简书项目实战-main首页开发
  15. RSRP为什么是负数
  16. 淘宝客如何通过闲鱼引流?如何抓住用户眼球实现精准引流?
  17. 区块链系统:点对点交易原理
  18. 大学四年,因为看了这些书,我大二就拿了华为Offer
  19. 通达信除权除息(tdx gbbq)导出为文本文件
  20. 前端学习之React篇-(1)最简React——Html直接引用React

热门文章

  1. 找到二叉树中的最大搜索二叉子树
  2. x12arima季节调整方法_降低农村生活污水处理设备运营成本的方法
  3. Begin Your Service Journey
  4. 函数的使用——未完待续
  5. SpringMVC的概念
  6. CTFshow php特性 web110
  7. android的shadowRadius属性说明
  8. sdut 2127 树-堆结构练习——合并果子之哈夫曼树 优先队列
  9. java中insert函数
  10. Laplacian Eigenmaps 拉普拉斯特征映射