10.操作系统演进过程

【README】

1.本文内容总结自 B站 《操作系统-哈工大李治军老师》的《操作系统的那棵树》,内容非常棒,墙裂推荐;

2.思维僵化与发散

the mind is not a vessel that needs filing, but wood that needs igniting.
头脑不是需要归档的容器,而是需要点燃的木头。

3.发散思维(与各位共勉)

  • 单向思维:灯丝材料出了问题,换其他材料吧;
  • 发散思维:会不会是外部环境的问题,而不是灯丝本身问题。如 真空环境? 问题的维度发生改变

【1】cpu运转起来

要管理cpu,就要使用cpu;
如何使用cpu?
为pc寄存器设置初值,然后cpu进行取指执行;


【2】cpu运转效率低

cpu执行一会,就需要等待一段时间,效率低;如 操作io,cpu需要阻塞等待io响应;

  • 以操作磁盘为例,cpu向磁盘控制器发送请求磁盘数据请求,磁盘磁头需要寻址到具体位置,读取数据到缓冲区,准备好数据后,磁盘控制器才会通知cpu说数据准备好了;

在 磁盘被请求到磁盘准备好数据这一段时间,cpu都只能等待阻塞,所以效率低


【3】 解决cpu运行效率低的问题

1)多个程序交替执行,解决cpu低效问题

  • 在程序1阻塞时,cpu切换到程序2继续运行;
  • 等待程序1阻塞结束后,再切换到程序1执行;

【注】本文程序指的是执行指令序列,其中执行序列可以称为线程,进程包含线程和执行资源


【4】多道程序交替执行的问题

从程序1跳转到程序2,结合栈来修改cpu的pc寄存器值;

当使用一个栈来实现程序切换,从程序1某条指令A切换到程序2,切换回程序1时,无法正确切换到指令A的下一条指令

【例1】cpu使用同一个栈进行多道程序切换(交替执行)的问题;

  • 程序1-函数A: 地址100的函数A在调用函数B前,把104压栈(以便返回后继续执行下一条指令,即地址104上的指令,下同),接着调用函数B;
  • 程序1-函数B: 地址200的函数B执行时,调用函数yield使得当前程序让出cpu给其他程序执行,先把204 压栈,再调用函数yield ;
  • 程序2-函数C: 因为程序1调用函数yield,所以cpu切换到程序2执行;调用程序2的地址300的函数C;函数C先把地址304压栈,再调用函数D;
  • 程序2-函数D: 执行函数D,先把地址404压栈,在调用函数yield 使得当前程序让出cpu给其他程序执行,如程序1;

【问题】函数D调用yield后,cpu会切换到程序1执行

  • cpu执行程序1的下一条指令是栈顶弹出的404地址上的指令,而不是程序1的下一条指令地址204; 这显然是不对的,因为404地址上的指令是程序2的,这就会造成程序执行终止的情况,因为整个程序状态不正确,上下文不正确;

(例1 如上图)


【解决方法】基于各自栈的多道程序切换(交替执行)方式

  • 每个程序各自单独使用一个内存栈,多个交替执行的程序互不影响;
  • 为了管理内存栈,操作系统引入了线程控制块tcb,tcb存储内存栈基址,栈指针等栈元素;
  • 对应地,函数yield修改为: 先找到程序2的tcb2,通过tcb2找到新栈2,进而切换到新栈2;

【小结】

操作系统引入的在多道程序中,每道程序使用单独的内存栈,解决了在用户态,多道程序切换的问题


 【5】内核态的多道程序切换问题

【5.1】背景

1)线程会从用户态进入内核态,内核态由于内存地址空间与用户态完全隔离,所以内核态无法查看到用户态的栈,也就无法切换到其他程序(进程或线程)

2)当内核态线程在执行过程中阻塞,cpu需要以某种方式切换到其他线程;这种方式就是 内核态的栈切换

  • 即 程序切换(进程切换或线程切换),需要切换一套栈,包括用户栈和内核栈;
  • 其中用户栈在用户态的内存地址空间,内核栈在内核态的内存地址空间;

3)内核态线程切换步骤

  • Step1)用户栈1切换到内核栈1;
  • Step2)通过内核栈1找到tcb1;
  • Step3)tcb1切换到tcb2;
  • Step4)通过tcb2找到内核栈2,并切换到内核栈2;
  • Step5)内核栈2切换到用户栈2;从而完成内核态的线程切换过程;


 【6】多道程序切换(用户态和内核态)的具体代码实现

【代码例子】

  • 在屏幕上交替打印出 A和 B ;

1)业务C代码  

main() {if (!fork()) {while(1) printf(“A”); }if (!fork()) {while(1) printf(“B”); }wait();
}

2)业务汇编代码

main() {mov __NR_fork, %eax // 系统调用编号 int 0x80  // 中断,展开后调用系统调用,进入内核 
100: mov %eax, res // 子线程的eax是0,父线程非0 cmpl res, 0 // res 与 0 比较 jne 208 // res不等于0,则跳到208 
200: printf("A") // 子线程代码 jmp 200 
208: ...   // 父线程代码 
304: wait()
}

3)调用步骤
Step1)INT中断进入内核
Int 0x80 中断,调用 system_call

system_call:

call _sys_call_table(%eax,4)

Step2)system_call 调用 sys_fork ;
Step3)sys_fork 调用 copy_process ;

sys_fork:

  pushl ……

  call copy_process

  ret

Step4)copy_process 代码细节

  • copy_process根据父线程的模样做出了子线程,包括TCB,新的内核栈;
  • 把TCB中的tss都初始化好,把用户栈与内核栈关联起来,tss存储了父线程执行时的物理寄存器的值,包括eip=100(父进程当前执行指令的下一条指令的地址),esp(栈指针),eax=0;
copy_process(... long eip, ...) // 参数列表为寄存器值列表
{p = (PCB*) get_free_page();p->tss.esp0 = p+4k;p->tss.esp = esp;p->tss.eax = 0;p->tss.eip = eip;... 
}

Tss 赋值:

Tss->eip=100

父线程当前执行指令的下一条指令的地址;

Tss->esp=p+4k

根据pcb内存起始地址,偏移4k得到内核栈起始地址;

Tss->esp=esp

Tss->eax=0

子线程tss的eax元素等于0,与父线程非0区分开;


 【6.1】父线程创建完第一个子线程后返回

1)业务C代码 

main() {if (!fork()) {while(1) printf(“A”); } // 创建第1个子线程if (!fork()) {while(1) printf(“B”); } // 创建第2个子线程 wait();
}

2)业务汇编代码

main() {mov __NR_fork, %eax // 系统调用编号 int 0x80  // 中断,展开后调用系统调用,进入内核 
100: mov %eax, res // 子线程的eax是0,父线程非0 cmpl res, 0 // res 与 0 比较 jne 208 // res不等于0,则跳到208 
200: printf("A") // 子线程代码 jmp 200 
208: ...   // 父线程代码 
304: wait()
}

3)父线程调用fork 创建完第1个子线程后,接着调用fork创建第2个子线程;
4)最后,父线程执行wait() 等待,让出CPU,让子线程执行

main() 
{...... wait(); 
}C代码wait()函数的汇编代码:
mov __NR_waitint 0x80 
system_call:call sys_waitpid
sys_waitpid() // exit.c 文件中;current->state = TASK_INTERRUPTIBLE;schedule(); // 调度

5)schedule()调度函数的汇编代码,调用switch_to() 函数

schedule()
{if ((*p)->state == TASK_RUNNING && (*p)->counter > c) c = (*p) -> counter;next = i; // 选择一个线程,作为切换到的目标线程 ...switch_to(next); 
}

6)switch_to()函数


主程序运行线程A打印字符A;
目标是交替打印A和B,而不仅仅打印A;


【6.2】交替打印A和B(时钟中断)

1)借助时钟中断,把线程A切换到线程B;
2)时钟中断C代码:

void sched_init(void) // 在 sched.c 中 
{set_intr_gate(0x20, &timer_interrupt);
}void timer_interrupt:...call do_timer void do_timer(...)
{// 当前线程时间片计数先减去1,然后判断其值 是否大于0,若大于0则返回;  if ( (--current->counter > 0) ) return ; current->counter = 0; // 若等于或小于0 则 切换到其他线程 schedule(); 
}

【代码解说】

  • 若 线程A时间片等于0,则切换到线程B打印字符B;

【补充】

  • 只要为每个线程(如线程A,线程B)设置时间片初值;
  • 每次调用该值都会减1;
  • 减1后,若时间片值小于等于0,则切换到其他线程执行,进而实现线程交替切换,交替执行的场景,即交替打印AB;


【小结】操作系统演进过程

  • 第一阶段:  让cpu运行起来;
  • 第二阶段:  多道程序交替运行,解决cpu运行低效问题;
  • 第三阶段: 引入了栈切换,每道程序独享一套栈(用户栈+内核栈),切换栈(用户栈+内核栈)达到切换多道程序的目的,使得程序可以交替运行;
    • 也可以说,切换栈就是切换内核栈,因为 内核栈切换包含了 用户栈的切换;
  • 第四阶段: 程序切换的触发条件有很多,本文引入了时钟中断来实现;
    • 为每个程序1设置一个时间片初始值,时钟每拨一次,时间片值减1,若值等于0,则切换到其他程序2;
    • 同样,程序2的运行也有一个上限时间片;一旦时间片等于0,则切换到其他程序3;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/329492.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Oracle入门(十二I)之误删除数据的恢复方法

转载自 oracle误删除数据的恢复方法今天主要以oracle数据库为例,介绍关于表中数据删除的解决办法。(不考虑全库备份和利用归档日志)删除表中数据有三种方法:delete(删除一条记录)drop或truncate删除表格中数…

Oracle入门(七A)之表空间配额(quota)

转载自 oracle表空间配额(quota)一、quota相关视图 1)dba_ts_quotas(查看所有用户的表空间配额) BYTES字段表示用户已经使用的空间;MAX_BYTES如果为-1表示没有限制,其他值表示限制配额 --只有用alter user user_name quota on tab…

python嵌套列表字典_python中嵌套列表转为字典

题目:# 有一组用例数据如下:cases [[case_id, case_title, url, data, excepted],[1, 用例1, www.baudi.com, 001, ok],[4, 用例4, www.baudi.com, 002, ok],[2, 用例2, www.baudi.com, 002, ok],[3, 用例3, www.baudi.com, 002, ok],[5, 用例5, www.ba…

.NET之全平台一体化的体验

一、前言 近来利用空闲时间研究了一下Xamarin的技术,想想既然提供了如此好的支持,就该尝试一切可能,来一个”大小通吃“。 何为全平台:APP包括Android、IOS、WP,WEB可在Window和Linux部署运行(进可攻,退可守…

11.cpu调度策略与schedule调度函数

【README】 1.本文内容总结自 B站 《操作系统-哈工大李治军老师》,内容非常棒,墙裂推荐; 2.cpu调度: 指的是 cpu从就绪队列中选择一个进程来执行;选择哪一个进程是调度算法的执行结果; 3. 相关定义&…

Oracle入门(十二)之SQL的DDL

一、数据类型 Character 数据类型Number 数据类型Date 数据类型Raw 和 Long Raw 数据类型 LOB 数据类型 注:Oracle数据类型详解二、表 (1)创建表 create table emp ( emp_id char (10) primary key, emp_name varchar2 (30), sal number (…

2016微软开发者峰会在京举办 纳德拉要来做演讲

还有不到一个月的时间,2016 微软开发者峰会就要在北京举办了。 在这场开发者的盛会上,微软 CEO、技术牛人,还有来自微软亚洲研究院、亚太研发集团、Xamarin 团队以及微软中国开发体验的专家们将对各平台的开发进行技术探讨。 据了解&#xff…

centos 卸载ffmpeg_Linux下ffmpeg的完整安装

最近在做一个企业项目, 期间需要将用户上传的视频转成flv格式或mp4格式并用flash插件在前端播放, 我决定采用ffmpeg (http://www.ffmpeg.org/ )实现. 当然以前也用过ffmpeg, 但是没有安装额外的库, 只是源代码下简单地 ./configure, 最后发现好多功能都用不了, 比如最流行的x26…

1.概率论-组合分析

【README】 本文总结自《概率论基础教程》 by M.Ross ,墙裂推荐; 【1.3】排列(考虑顺序) 1)例3d: 用6个字母 PEPPER排列,共有多少种不同的排列方式? 2)推理 对于n个元素,如果其中n1个元素相同,其他n2个元素相同,......,nr个元素也相同,一共有 种不同排列方式;…

Oracle入门(十二B)之表创建

一、创建表(1)简单表 Create Table emp (Emp_id char(10) primary key,Emp_name varchar2(30),Sal number(5),Tel varchar2(20) ); (2)带参数的表格创建 create table emp (emp_id char (10) primary key,emp_name varchar2 (30),…

我的创作纪念日:感恩、感谢、感激!

/bin/bash 机缘 感恩、感谢、感激! 第一次进入到csdn,还是当初老师傅叫我们可以借鉴一下这里的文章 所以! 一开始进入到csdn网站,还以为这里也是和某些贴吧一样,一样的灌水呢! 但是正式在这里书写文章之后&#…

python中seaborn画swarm图_Python可视化 | Seaborn5分钟入门(四)——stripplot和swarmplot

微信公众号:「Python读财」如有问题或建议,请公众号留言Seaborn是基于matplotlib的Python可视化库。 它提供了一个高级界面来绘制有吸引力的统计图形。Seaborn其实是在matplotlib的基础上进行了更高级的API封装,从而使得作图更加容易&#xf…

第四篇 Entity Framework Plus 之 Batch Operations

用 Entity Framework 进行 增,删,改。都是基于Model进行的,且Model都是有状态追踪的。这样Entity Framework才能正常增,删,改。 有时候,要根据某个字段,批量更新或者删除数据,用Ent…

2.概率论-概率论公理

【README】 本文总结自《概率论基础教程》 by M.Ross ,墙裂推荐; 【2.2】样本空间和事件 1)样本空间 所有可能的结果构成的集合,称为该实验的样本空间,记为S;2)事件(一个集合,或样本空间的子集) 样本空间的任一子集E称为事件;或样本空间中选取若干个结果构成的集合…

Oracle入门(十二C)之表修改

一、列操作 (1)添加列alter table 表名 add (列名 数据类型 [default 表达式], ..);alter table tableName add temp varchar2(30);(2)修改列A.修改列类型和属性alter table 表名 modify (列名 数据类型 [default 表达式], ..)…

在ThoughtWorks工作12年的技术主管,所总结的12条技术人经验

原文: 12 years, 12 lessons working at ThoughtWorks 作者: Patrick,ThoughtWorks的技术主管兼敏捷顾问 编译: 孙薇 本文作者在ThoughtWorks工作了12年之久, 回顾了往昔工作之后,他得出了12条经验心得&…

3.条件概率与独立性

【README】 本文总结自《概率论基础教程》 by M.Ross ,墙裂推荐; 【3.2】条件概率 1)条件概率定义: 【补充】条件概率计算示例 【3.3】贝叶斯公式 1)通过第2个事件发生与否计算第1个事件的概率(非常重要…

python安装运行时提示不是内部或外部命令怎么办_如何解决cmd运行python提示不是内部命令...

python安装完成后,直接运行python.exe能够正常执行python程序。但是进入到cmd命令窗口(同时按下winr组合键后输入cmd进入),输入python命令提示“不是内部或外部命令”,遇到这种现象通常是没有将python的安装路径添加到环境变量中。在桌面上右…

Oracle入门(十二D)之表删除与删除表数据

一、删除表 drop table 表名; drop table t_userinfo;二、删除表数据 (1)DML操作deletedelete from 表名;(2)DDL操作truncatetruncate table 表名;三、恢复 (1)恢复删除的表 Oracle 10g提供恢复操作 flashb…

.NET Core VS Code 环境配置

VSCode .NET环境配置 在此之前我一直是使用notepad配置的C/C#环境来写代码,比起打开"笨重"的VS要方便很多.VSCode出来之后,本来也想折腾了一下,但是当时资料太少,配置没成功,也觉notepad就已经够了. 直到前几天在博客园看到园友LineZero分享的<<使用VS Code开发…