【操作系统一】操作系统概述

目录

一、课程地位

 二、问题

三、操作系统起源与发展(方法与效率)

1. 没有操作系统的时代

2. 冯诺依曼计算机体系结构

3. 硬件编程

4. 操作系统方法

(1) 早期多人使用计算机

(2) 改进:单道批处理系统

(3) 解决:多道批处理系统

(4) 解决:分时操作系统(交互式系统)

        (4) 综上!逻辑梳理

6. 内核态与用户态,特权指令与非特权指令

7. 处理中断

四、课程安排


一、课程地位

 二、问题

        在学完整节课之后可以回头看看这些问题,自己心中会有答案。

1. EXE、ELF是什么?运行一个EXE到底发生了什么?

2. c库函数是如何实现的(printf、scanf、gets)?fread和read的区别是什么?

3. 我的破烂电脑512M内存,怎么4G的游戏也可以跑?(虚拟内存啥东西?)

4. 图中程序在运行时,CPU利用率是多少?

        早期单核CPU是100%。

 5. 该内存不能为written? 这是什么意思?内存坏了?“写保护” 打开了? 此应用程序还可以继续执行吗? 该错误是哪个设备第1个发现的?CPU,内存,或是其他?处理流程是什么?

6. 需要通信的程序:C/Java的应用程序数据,用matlab脚本进行分析 如何传送数据?原理是什么?有更高效的方法?

7. 浏览器:IE vs Chrome。为什么早期的IE浏览器,打开一个页面崩溃了,其他页面也跟着崩溃了? google的Chrome浏览器和IE后期版本是如何解决这个问题的? 

8. 诡异的bug:我写了一个程序,测试都通过了,上线后跑了一个月运行正常,后来时不时的无法响应客户端的请求,出现的频率非常随机,但在任务管理器里却能看到这个程序。 因为难以重现,我被这个问题折磨得头发都白了,想死的心都有了。

9. 数据恢复:在磁盘上被 删除的数据,还有可能被人恢复,为什么? 操作系统本可以避免数据被恢复,但没有做,为什么?

10. 怎么样才能学好操作系统?

三、操作系统起源与发展(方法效率)

1. 没有操作系统的时代

        1946(第一台计算机诞生,那时候还没有操作系统):通过拨开关编程。麻烦!

2. 冯诺依曼计算机体系结构

        程序存储,顺序执行

        思路:让计算机要做的事情编成程序放在硬盘(disk)or磁带上面,计算机运行之后将程序装载到内存里面,由CPU一条条指令从内存取出并执行,完成最终想让计算机完成的任务。

        仍然没有操作系统,编程麻烦。

        外设并不是直接连到总线上,而是通过控制器(例如monitor通过graphics controller)连到总线上与CPU互连。

        我们与外设的交互是通过这些controller,并不是直接与外设打交道。

3. 硬件编程

        controller结构如下:
       

         当想操作打印机时,找到打印机的controller,将命令(二进制01串)写道command register。因此控制外设需要查他的控制器手册,告诉你些什么样的指令对应什么样的功能。status register对应的是外设状态,全0正常,某一位置异常那一位会返回1。

        但是对于不同外设的controller编程不同,仍较为复杂。

4. 操作系统方法

(1) 对开发人员:屏蔽了底层硬件的复杂性

        原始:APP内程序通过查controller手册来控制HW(硬件)。

        加入操作系统(OS软件):OS与HW交互(OS的驱动程序完成,驱动程序代码占80%-90%),APP通过C或汇编调用OS接口(比如fread等操作系统提供的一系列函数)。

        因此开发人员不需要关心底层逻辑,只需调用OS接口(即系统调用system call)即可。

(2) 对小白用户:提供了良好的人机交互界面。

5. 操作系统效率

(1) 早期多人使用计算机

        人工操作:将每个人的程序放到磁带上(打孔),交给计算机管理员(人工),计算机管理员将每个人的磁带分别放到计算机上运行,并将结果再交给各个人。

        缺点:手动更换任务、耗时容易出错 。

(2) 改进:单道批处理系统

        在这台计算机上一直跑一个监督程序,他会扫描外设上有没有任务,有任务就将他加载到内存中执行直至结束,后再扫描...

        问题:例如P(I1, C1, O1, I2, C2, O2, .. )(Input -> Compute -> Output),发现C步骤非常快(≈2.6GHz,ns级),但IO(200-300ms)的速度比C慢的多得多得多。存储介质访问速度:

         因此CPU利用率很低(当一个任务在执行IO操作时,CPU是空闲的)。

(3) 解决:多道批处理系统

        一次载入多道程序到内存。eg:P1(I1, C1, O1), P2(I2, C2, O2)。I1I2已执行完毕,C1 -> O1+C2(一边输出一边运算)。即一个job在做IO时,切换另一个job来运行。

        程序切换的条件:当前程序要做IO操作。

        优点:提高了CPU利用率。缺点:任务周转时间(从提交任务至获得输出的时间)太长!例如:job1=科学计算,job2=游戏。先双击job1再双击job2,然而job1这个科学计算要执行一个月,这样你的job2游戏智能一个月之后才会启动(因为不做IO不会切换程序运行)。

(4) 解决:分时操作系统(交互式系统)

        显然我们不能被动的等待程序切换,而要主动地定时地去切换程序。程序切换的时间不由程序本身的IO决定,而由时间片决定。(将CPU的时间切割成小的时间片,每个程序交互式的占用时间片执行。早期linux时间片 = 20ms,由CPU时钟中断处理程序完成程序的切换)

         并发执行和并行执行:

         问题1(也是多道批处理系统的问题):看下面两个程序:

int a=1;            int b=3;
void main() {       void main() {
	a++;            	b--;
}                   }

        如果不从底层机器的视角看,这两个程序并发执行没有任何问题!但:

int a=1;            int b=4;
void main() {       void main() {
	a++;            	b--;
}                   }

1 MOV AX, [a]       4 MOV AX,[b]
2 ADD AX            5 DEC AX
3 MOV [a], AX       6 MOV [b], AX 

a = 2               b = 3

        本来应该按上述顺序执行(123456),但分时操作系统会主动将程序踢出切换到另一个程序,因此会出现下述情况:

int a=1;            int b=4;
void main() {       void main() {
	a++;            	b--;
}                   }

情况1
1 MOV AX, [a]       3 MOV AX,[b]
2 ADD AX            4 DEC AX
5 MOV [a], AX       6 MOV [b], AX 
a = 3               b = 3

情况2
1 MOV AX, [a]       2 MOV AX,[b]
3 ADD AX            4 DEC AX
5 MOV [a], AX       6 MOV [b], AX 
a = 4               b = 4

等等

        问题2(也是多道批处理系统的问题):不共用寄存器行吗?(对同一全局变量不同程序先后修改。)

int a=1;            
1 void main() {     2 void main() {
	a++;            	a--;
}                   }

1 MOV AX, [a]       3 MOV BX,[a]
2 ADD AX            4 DEC BX
5 MOV [a], AX       6 MOV [a], BX
原本:a = 2          a = 1
结果:a = 2          a = 0

        解决:引入锁机制。

int a=1;            
1 void main() {     2 void main() {
	lock(a);            lock(a);
    a++;            	a--;
    unlock(a);          unlock(a);
}                   }

        P1把c锁住,当时间片到了切换到P2,P2也想锁c,但c已经被P1锁了P2就锁不上了,所以卡在那不能接续执行,知道时间片切换回P1,使其运行到unlock(c),P2就可以接着运行,因此不会出现上述问题。

        问题:锁机制带来的问题:死锁。执行顺序如上,1、2执行完毕后,3、4均卡住,于是P1P2陷入等待对方的死锁之中。

            int a=1, b=1;            
void main() {       void main() {
	1 lock(a);          2 lock(b);
    3 lock(b);          4 lock(a);
    a++;            	a--;
    b++;                b--;
    unlock(b);          unlock(a);
    unlock(a);          unlock(b);
}                   }

        (4) 综上!逻辑梳理

        单道批处理效率低 -> 提高效率:穿插运行 -> 共享寄存器问题 -> 共享全局变量问题 -> 加锁不穿插运行 -> 死锁问题。归根结底:一台计算机上跑多道程序(否则只跑一道程序的话,此门课就可以到此为止了hhh)。

6. 内核态与用户态,特权指令与非特权指令

        CPU状态:内核态与用户态 -> 特权指令与非特权指令

        你写的应用程序所用到的指令均为非特权指令,特权指令只有操作系统可用,例如,IO指令in/ out,关中断开中断指令cli/sti 如果应用程序直接使用特权指令,报错。如下:

        计算机上电先跑操作系统代码,此时CPU状态为00,在将P1调入运行前将CPU状态改为11,然后将CPU让给P1运行,在执行P1是遇到修改控制器(主要是修改硬件控制器的指令)等特权指令就报错。防止APP越过OS直接操控HW。

        内核态:从上电到OS执行期间(此时CPU是开放状态,啥指令都能执行)。

        用户态:执行完OS代码,开始执行APP指令的时候,此时CPU受限,特权指令无法执行。

        OS->APP : CPU=11; APP -> OS : CPU=00。

        若用户程序的功能需要特权指令,如IO? 向操作系统发出请求,称为系统调用(System call)。每个操作系统均需要提供一些系统调用,不同操作系统提供的系统调用不一样(这是应用程序不能跨平台运行的重要原因)

7. 处理中断

        中断发生时,由操作系统先处理,再转发给相应的用户程序,例如:键盘上按下一个键。回忆:中断控制器、中断处理程序(设备驱动程序提供)、应用程序 。

        上述中断为硬件中断(interrupt),陷入(trap)的机制与硬件中断类似,用于实现系统调用,又称为软中断。如果操作系统要“剥夺” 一个程序的CPU,让CPU去执行另外一个程序,如何做到? 让定时器周期性产生时钟中断(时间片)。

        综上,再总结一下:操作系统的运行:1. 计算机启动时,启动内核模式、设置中断处理程序、创建用户进程、设置定时器周期性唤醒自己;2. 从内核模式切换到用户模式,运行用户程序;3. 中断(硬件或软件)来临时,从用户模式升级为内核模式,操作系统重新掌握CPU,处理完毕后降级为用户模式,运行用户程序。

四、课程安排

        1. 管理CPU——进程管理;

        2. 管理内存——内存管理;

        3. 管理外存——存储管理;

        4. 管理外设——I/O;

        Linux操作系统内核: 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值