Linux操作系统简介

Linux拥有现代操作系统的功能,如真正的抢先式多任务处理,支持多用户内存,保护虚拟内存,支持SMP、UP,符合POSIX 标准联网、图形用户接口和桌面环境具有快速性、稳定性等特点。本文通过分析Linux内核源代码,说明了Linux作为操作系统内核是如何对进程组织,转换,调度的。

进程的组织

进程在内核中是以PCB的形式存在的,一个操作系统有很多进程,即就是很多PCB同时存在,如何有效的管理进程的组织方式,显然是一个很重要的问题,为了遍历内核中所有的进程,内核将这些PCB直接用双向链表链起来,task_struct 结构中的tasks字段就是用来连接所有进程描述符的。在这个链中,链表头是init_task描述符,它是所谓的0进程或者swapper进程的描述符,init_task.tasks.prev字段指向链表中最后插入的进程描述符的tasks字段。

struct task_struct {
struct list_head run_list;
struct list_head tasks;
struct task_struct *real_parent; /*real parent process (when being debugged) */
struct task_struct *parent; /* parent process */
struct list_head children; /* list of my children */
struct list_head sibling; /* linkage in my parent's children list */
struct task_struct *group_leader; /* threadgroup leader */
/* PID/PID hash table linkage. */
struct pid_link pids[PIDTYPE_MAX];
struct list_head thread_group;
};

从以上源代码中的字段可知Linux是如何组织进程的。

字段run_list:
在内核中有一个队列是可运行队列,即就是保存了进程状态为:TASK_RUNNING的进程PCB,这个队列就是run_list字段,内核为每个优先级都设置了一个可运行队列,即如果一个进程的优先级为k(取值范围是0到139),那么内核就将此进程链入到优先权为k的可运行队列中,这样CPU可以从高优先级可可运行队列去选择要运行的进程,这样提高了效率,但为此却要把所有可运行的进程队列拆分成140个不同的队列。这些队列有一个单独的数据结构prio_array_t数据结构 来实现,定义如下(摘自linux2.6.11):

typedef struct prio_array prio_array_t;
struct prio_array {unsigned int nr_active;unsigned long bitmap[BITMAP_SIZE];struct list_head queue[MAX_PRIO];
};

字段 children、 sibling和thread_group:
这三个字段分别是进程的子进程链表、兄弟链表和线程组链表。可以根据children和sibling字段找到一个进程家族的进程。进程在创建后必须处于某一个组中,通过thread_group来形成一个进程组。

进程的转换

Linux中进程切换过程与函数调用堆栈基本类似

void my_schedule(void)
{tPCB * next;tPCB * prev;if(my_current_task == NULL || my_current_task->next == NULL){return;}printk(KERN_NOTICE ">>>my_schedule<<<\n");/* schedule */next = my_current_task->next;prev = my_current_task;/*进程上下文的切换,与函数调用堆栈类似*/if(next->state == 0)/* -1 unrunnable, 0 runnable, >0 stopped */{/* switch to next process */asm volatile(/*保存当前进程的ebp esp*/  "pushl %%ebp\n\t"       /* save ebp */"movl %%esp,%0\n\t"     /* save esp *//*构建下一个进程的esp*/"movl %2,%%esp\n\t"     /* restore  esp *//*$1f是指下面标号为1的位置,就是下一个进程启动的位置*/"movl $1f,%1\n\t"       /* save eip */ /*下一个进程eip压栈*/"pushl %3\n\t" /*恢复现场:eip指向下下个进程的地址ebp恢复为第一条指令压栈保存的ebp*/"ret\n\t"               /* restore  eip */"1:\t"                  /* next process start here */"popl %%ebp\n\t": "=m" (prev->thread.sp),"=m" (prev->thread.ip): "m" (next->thread.sp),"m" (next->thread.ip)); my_current_task = next; printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);      }else{next->state = 0;//新的进程设置为正在运行状态my_current_task = next;printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);/* switch to new process */asm volatile(   "pushl %%ebp\n\t"       /* save ebp */"movl %%esp,%0\n\t"     /* save esp *//*新的进程从来没有执行过,所以栈为空esp与ebp指向同一位置*/"movl %2,%%esp\n\t"     /* restore  esp */"movl %2,%%ebp\n\t"     /* restore  ebp */"movl $1f,%1\n\t"       /* save eip */ "pushl %3\n\t" "ret\n\t"               /* restore  eip */: "=m" (prev->thread.sp),"=m" (prev->thread.ip): "m" (next->thread.sp),"m" (next->thread.ip));          }   return;
}

切换过程:

1.保存当前进程的堆栈环境(esp,eip,ebp),首先将当前进程的ebp压栈,并将esp和eip保存在当前进程的结构体中

2.构建下一进程的堆栈环境。然后下一条进程的thread.sp读出,赋给esp;thread.ip读出赋给eip。若下一条进程是新的进程,处于未运行状态,则新进程堆栈为空,esp与ebp指向同一地址,这种情况与函数调用堆栈更加类似。若下一条进程处于运行态,那么ebp与当前进程的ebp指向同一地址。

3.恢复堆栈环境,为下下个进程做准备。恢复eip,即把执行完成的进程的thread.ip(下一进程的指令地址)赋给eip,上例中所有进程的thread.ip设为my_process。

如图所示:

进程的调度

Linux系统进程提供了两种优先级,一种是普通的进程优先级,第二个是实时优先级。前者适用SCHED_NORMAL调度策略,后者可选SCHED_FIFO或SCHED_RR调度策略。任何时候,实时进程的优先级都高于普通进程,实时进程只会被更高级的实时进程抢占,同级实时进程之间是按照FIFO(一次机会做完)或者RR(多次轮转)规则调度的。

Linux进程状态机:

个人看法

在日常使用手机或者电脑的时候,经常在将应用关闭或退出后,仍然还有许多进程在后台运行,促使我对进程的存在产生了好奇心。现在明白,不仅仅在应用运行时会产生进程,计算机系统本身在运行过程中也会产生许多进程,就是这些进程使得计算机可以调用许多功能,与人进行交互。而通过对Linux操作系统进程的探索,使我对进程有了更进一步的了解,懂得了为什么计算机可以同时运行那么多程序,好的进程的组织,转换和调用模式可以极大地提升计算机的性能,帮助我们更好地完成任务。

转载于:https://www.cnblogs.com/zhengzhihuang/p/8966846.html

Linux操作系统进程模型分析相关推荐

  1. linux RTC 驱动模型分析

    linux RTC 驱动模型分析 RTC(real time clock)实时时钟,主要作用是给Linux系统提供时间.RTC因为是电池供电的,所以掉电后时间不丢失.Linux内核把RTC用作&quo ...

  2. linux MISC 驱动模型分析

    linux MISC 驱动模型分析 阅读led驱动程序的代码的时候,没有发现ldd3中提到的各种字符设备注册函数,而是发现了一个misc_register函数,这说明led设备是作为杂项设备出现在内核 ...

  3. LINUX设备驱动模型分析之三 驱动(DRIVER)接口分析

    上一章我们分析了bus-driver-device模型中bus接口部分,本章我们将分析driver接口,在bus-driver-device模型中,driver接口是依附于bus上,而不像device ...

  4. linux platform 驱动模型分析

    一. 概述     platform设备和驱动与linux设备模型密切相关.platform在linux设备模型中,其实就是一种虚拟总线没有对应的硬件结构.它的主要作用就是管理系统的外设资源,比如io ...

  5. Linux RTC驱动模型分析之rtc-sysfs.c【转】

    转自:https://blog.csdn.net/longwang155069/article/details/52353408 版权声明:本文为博主原创文章,未经博主允许不得转载. https:// ...

  6. Linux操作文档——分析和排查系统故障(日志)

    文章目录 一.日志系统 1.概念 2.分类 二.分析日志文件 1.主要日志文件 2.日志文件分析 3.action(动作)日志记录的位置 三.日志的采集 1.一般日志采集 2.Nginx日志采集 3. ...

  7. cupsd进程_关于Linux操作系统进程操作(ps)命令简介

    1.ps 进程状态查询命令. 命令格式#ps [[选项]] 常用选项: ● -a,显示所有用户进程. ● -e,显示进程环境变量. ● -l,给出长列表. ● -r,只显示正在运行的进程. ● -S, ...

  8. 深入浅出Linux操作系统进程管理与rpm包管理(四)

    ✍.目录脑图 笔记参考视频为韩顺平老师的Linux2021年度课程:B站链接直达 当前采用 centos 7.6 虚拟机环境搭建,之后进行服务器真实环境记录 深入浅出Linux操作系统

  9. linux i2c adapter 增加设备_LINUX设备驱动模型分析之四 设备模块相关(DEVICE)接口分析...

    本系列前几篇文章链接如下: <LINUX设备驱动模型分析之一 总体概念说明> <LINUX设备驱动模型分析之二 总线(BUS)接口分析> <LINUX设备驱动模型分析之三 ...

最新文章

  1. 36晋级12第五场:冯志刚决胜入围(节目视频)
  2. Boost库学习(0)
  3. 窗口类、窗口类对象与窗口 三者之间关系
  4. 祝贺 在线文件管理系统 访问量 超过500
  5. 同步异步多线程这三者关系,你能给面试官一个满意的回答吗?
  6. struts+hibernate+oracle+easyui实现lazyout组件的简单案例——struts.xml配置详情
  7. 【网络基础】《TCP/IP详解》学习笔记6
  8. java归并算法实例_Java编程中实现归并排序算法的实例教程
  9. 李宏毅自然语言处理——Self Attention
  10. iBatis.Net系列(五)-providers.config-
  11. 银行卡号 归属地大全
  12. MATLAB人脸识别区域定位实战源码解析
  13. linux 中文转unicode,Linux下汉字编码的转换
  14. Markdown 数学公式
  15. 什么是Alpha通道?
  16. Your Command Line Tools are too outdated
  17. MAC欺骗-通过思科模拟器实现
  18. NGUI Sprite的各种Type(Simple、Sliced、Tiled、Filed、Advanced)
  19. matlab的trial,Free Product Trial - MATLAB Simulink
  20. 加权平均资本成本【读书笔记】

热门文章

  1. 用mysql web建立论坛_在web1上搭建Discuz论坛
  2. python扫雷脚本_Python自动扫雷实现方法
  3. sql sum求和 值小于不显示_mysql中sum求和等类似方法关于null值的处理
  4. java locale string_Java Locale toString()用法及代码示例
  5. c语言数组与指针编程源码,C语言编程(练习9:数组与指针)
  6. Anaconda不同平台的安装方式
  7. Python教程(非常好的教程)
  8. 特征选择的工程方法?
  9. Volatile(理解)
  10. spark-shell开发wordcount程序