操作系统

操作系统

一. 什么是冯诺伊曼体系
二.内存管理
三.进程管理
四.文件管理
五.输入输出管理
1.冯诺伊曼体系简介
现代计算机之父冯诺伊曼最先提出程序存储的思想,并成功将其运用在计算机的设计之中,该思想约定了用二进制进行计算和存储,还定义计算机基本结构为 5 个部分,分别是中央处理器(CPU)、内存、输入设备、输出设备、总线
在这里插入图片描述
存储器:代码跟数据在RAM跟ROM中是线性存储, 数据存储的单位是一个二进制位。最小的存储单位是字节。
总线:总线是用于 CPU 和内存以及其他设备之间的通信,总线主要有三种:

地址总线:用于指定 CPU 将要操作的内存地址。
数据总线:用于读写内存的数据。
控制总线:用于发送和接收信号,比如中断、设备复位等信号,CPU 收到信号后响应,这时也需要控制总线。
输入/输出设备:输入设备向计算机输入数据,计算机经过计算后,把数据输出给输出设备。比如键盘按键时需要和 CPU 进行交互,这时就需要用到控制总线
CPU:中央处理器,类比人脑,作为计算机系统的运算和控制核心,是信息处理、程序运行的最终执行单元。CPU用寄存器存储计算时所需数据,寄存器一般有三种:
通用寄存器:用来存放需要进行运算的数据,比如需进行加法运算的两个数据。
程序计数器:用来存储 CPU 要执行下一条指令所在的内存地址。
指令寄存器:用来存放程序计数器指向的指令本身。
在冯诺伊曼体系下电脑指令执行的过程:
CPU读取程序计数器获得指令内存地址,CPU控制单元操作地址总线从内存地址拿到数据,数据通过数据总线到达CPU被存入指令寄存器。
CPU分析指令寄存器中的指令,如果是计算类型的指令交给逻辑运算单元,如果是存储类型的指令交给控制单元执行。
CPU 执行完指令后程序计数器的值通过自增指向下个指令,比如32位CPU会自增4。
自增后开始顺序执行下一条指令,不断循环执行直到程序结束。
CPU位宽:32位CPU一次可操作计算4个字节,64位CPU一次可操作计算8个字节,这个是硬件级别的。平常我们说的32位或64位操作系统指的是软件级别的,指的是程序中指令多少位。
线路位宽:CPU操作指令数据通过高低电压变化进行数据传输,传输时候可以串行传输,也可以并行传输,多少个并行等于多少个位宽.
1.2 CPU 简介
Central Processing Unit 中央处理器,作为计算机系统的运算和控制核心,是信息处理、程序运行的最终执行单元。
在这里插入图片描述
CPU核心:一般一个CPU会有多个CPU核心,平常说的多核是指在一枚处理器中集成两个或多个完整的计算引擎。核跟CPU的关系是:核属于CPU的一部分。
寄存器:最靠近CPU对存储单元,32位CPU寄存器可存储4字节,64位寄存器可存储8字节。寄存器访问速度一般是半个CPU时钟周期,属于纳秒级别,
L1缓存:每个CPU核心都有,用来缓存数据跟指令,访问空间大小一般在32~256KB,访问速度一般是2~4个CPU时钟周期。
L2缓存:每个CPU核心都有,访问空间大小在128KB~2MB,访问速度一般是10~20个CPU时钟周期。
L3缓存:多个CPU核心共用,访问空间大小在2MB~64MB,访问速度一般是20~60个CPU时钟周期。
内存:多个CPU共用,现在一般是4G~512G,访问速度一般是200~300个CPU时钟周期。
固体硬盘SSD:现在台式机主流都会配备,上述的寄存器、缓存、内存都是断电数据立马丢失的,而SSD里不会丢失,大小一般是128G~1T,比内存慢10~1000倍。
机械盘HDD:很早以前流行的硬盘了,容量可在512G~8T不等,访问速度比内存慢10W倍不等
访问数据顺序:CPU在拿数据处理的时候几乎也是按照上面说得流程来操纵的,只有上面一层找不到才会找下一层。
Cache Line : CPU读取数据时会按照 Cache Line 方式把数据加载到缓存中,每个Cacheline = 64KB,因为L1、L2是每个核独有到可能会触发伪共享,就是 所以可能会将数据划分到不同到CacheLine中来避免伪共享,比如在JDK8 新增加的 LongAdder 就涉及到此知识点。
伪共享:缓存系统中是以缓存行(cache line)为单位存储的,当多线程修改互相独立的变量时,如果这些变量共享同一个缓存行,就会无意中影响彼此的性能,这就是伪共享。
JMM: 数据经过种种分层会导致访问速度在不断提升,同时也带来了各种问题,多个CPU同时操作相同数据可能会造成各种BU个,需要加锁,这里在JUC并发已详细探讨过。
怎么设计缓存的存放算法才能提高cache的利用率?
也就是采用什么算法将内存中哪些数据存放到缓存中?
举个别例子如下:
1、Least-Recently-Used(LRU) - 最近最少使用
替换掉最近被请求最少的文档。这一传统策略在实际中应用最广。在CPU缓存淘汰和虚拟内存系统中效果很好。
2、Least-Frequently-Used(LFU) - 最不经常使用
替换掉访问次数最少的。这一策略意图保留最常用的、最流行的对象,替换掉很少使用的那些。然而,有的文档可能有很高的使用频率,但之后再也不会用到。
3、SIZE
替换size最大的对象。这一策略通过淘汰一个大对象而不是多个小对象来提高命中率。不过,可能有些进入缓存的小对象永远不会再被访问。
多核CPU多级缓存一致性协议MESI
多核CPU的情况下有多个一级缓存,如何保证缓存内部数据的一致,不让系统数据混乱。这里就引出了一个一致性的协议MESI。
MESI 是指4中状态的首字母。每个Cache line有4个状态,可用2个bit表示,它们分别是:
缓存行(Cache line):缓存存储数据的单元。
在这里插入图片描述
缓存锁是基于此实现的 如果更新缓存–》通知另一个缓存的内容是无效的需要重新加载
2 内存管理
你的电脑是32位操作系统,那可支持的最大内存就是4G,你有没有好奇为什么可以同时运行2个以上的2G内存的程序。应用程序不是直接使用的物理地址,操作系统为每个运行的进程分配了一套虚拟地址,每个进程都有自己的虚拟内存地址,进程是无法直接进行物理内存地址的访问的。至于虚拟地址跟物理地址的映射,进程是感知不到的!操作系统自身会提供一套机制将不同进程的虚拟地址和不同内存的物理地址进行映射。
2.1 MMU
Memory Management Unit 内存管理单元是一种负责处理CPU内存访问请求的计算机硬件。它的功能包括虚拟地址到物理地址的转换内存保护中央处理器高速缓存的控制。现代 CPU 基本上都选择了使用 MMU。
当进程持有虚拟内存地址的时候,CPU执行该进程时会操作虚拟内存,而MMU会自动的将虚拟内存的操作映射到物理内存上。
在这里插入图片描述
2.2 内存管理方式

操作系统主要采用内存分段和内存分页来管理虚拟地址与物理地址之间的关系,其中分段是很早前的方法了,现在大部分用的是分页,不过分页也不是完全的分页,是在分段的基础上再分页。
分段式
分段映射很简单,但是会导致内存碎片跟内存交互效率低。这里先普及下在内存管理中主要有内部内存碎片跟外部内存碎片。
内部碎片:已经被分配出去的的内存空间不经常使用,并且分配出去的内存空间大于请求所需的内存空间。
外部碎片:指可用空间还没有分配出去,但是可用空间由于大小太小而无法分配给申请空间的新进程的内存空间空闲块。
内存分页
内存分页,整个虚拟内存和物理内存切成一段段固定尺寸的大小。每个固定大小的尺寸称之为页Page,在 Linux 系统中Page = 4KB。然后虚拟内存跟物理内存之间通过页表来实现映射。
采用内存分页时内存的释放跟使用都是以页为单位的,也就不会产生内存碎片了。当空间还不够时根据操作系统调度算法,可能将最少用的内存页面 swap-out换出到磁盘,用时候再swap-in换入,尽可能的减少磁盘刷写量,提高内存交互效率。
分页模式下虚拟地址主要有页号跟页内偏移量两部分组成。通过页号查询页表找到物理内存地址,然后再配合页内偏移量就找到了真正的物理内存地址。
段页式管理
内存分段跟内存分页不是对立的,这俩可以组合起来在同一个系统中使用的,那么组合起来后通常称为段页式内存管理。段页式内存管理实现的方式:
先对数据不同划分出不同的段,也就是前面说的分段机制。
然后再把每一个段进行分页操作,也就是前面说的分页机制。
此时 地址结构 = 段号 + 段内页号 + 页内位移。
每一个进程有一张段表,每个段又建立一张页表,段表中的地址是页表的起始地址,而页表中的地址则为某页的物理页号。
同时我们经常看到两个专业词逻辑地址跟线性地址。
1.逻辑地址:指的是没被段式内存管理映射的地址。
2.线性地址:通过段式内存管理映射且页式内存管理转换前的地址,俗称虚拟地址。
内核空间:操作系统内核访问的区域,独立于普通的应用程序,是受保护的内存空间。内核态下CPU可执行任何指令,可自由访问任何有效地址。
用户空间:普通应用程序可访问的内存区域。被执行代码会受到CPU众多限制,进程只能访问映射其地址空间的页表项中规定的在用户态下可访问页面的虚拟地址。
那为啥要搞俩空间呢?现在嵌入式环境跟以前的WIN98系统是没有区分俩空间的,须知俩空间是CPU分的,而操作系统是在上面运行的,单一用户、单一任务服务的操作系统,是没有分所谓用户态和内核态的必要。用户态和内核态是因为有多用户,多任务的需求,然后在CPU硬件厂商配合之后,产生的一个操作系统解决多用户多任务需求的方案。方案就是限制,通过硬件手段(也只能硬件手段才能做到),限制某些代码,使其无法控制整个物理硬件,进而使各个不同用户,不同任务的代码,无权修改整个物理硬件,再进而保护操作系统的核心底层代码和其他用户的数据不被无意或者有意地破坏和盗取。
在这里插入图片描述
后来研究者根据CPU的运行级别,分成了Ring0~Ring3四个级别。Ring0是最高级别,Ring1次之,Rng2更次之,拿Linux+x86来说, 操作系统内核的代码运行在最高运行级别Ring0上,可以使用特权指令,控制中断、修改页表、访问设备等。 应用程序的代码运行在最低运行级别上Ring3上,不能做受控操作,只能访问用户被分配的空间。如果要做访问磁盘跟写文件等操作,那就要通过执行系统调用函数,执行系统调用的时候,CPU的运行级别会发生从Ring3到Ring0的切换,并跳转到系统调用对应的内核代码位置执行,这样内核就为你完成了设备访问,完成之后再从Ring0返回Ring3。这个过程也称作用户态和内核态的切换。(权限切换)
用户态想要使用计算机设备IO需通过系统调用完成sys call,系统调用就是让内核来做这些操作。而系统调用是影响整个当前进程上下文的,CPU提供了个软中断来是实现保护线程,获取系统调用号跟参数,交给内核对应系统调用函数执行。
在这里插入图片描述
可以看到每个应用程序都各自有独立的虚拟内存地址,但每个虚拟内存中对应的内核地址其实是相同的一大块,这样当进程切换到内核态后可以很方便地访问内核空间内存。
3 进程管理
3.1 进程基础知识
进程是程序的一次执行,是一个程序及其数据在机器上顺序执行时所发生的活动,是具有独立功能的程序在一个数据集合上的一次运行过程,是系统进行资源分配和调度的一个基本单位。进程的调度状态如下:
在这里插入图片描述
重点说下挂起跟阻塞:
阻塞一般是当系统执行IO操作时,此时进程进入阻塞状态,等待某个事件的返回。
挂起是指进程没有占有物理内存,被写到磁盘上了。这时进程状态是挂起状态。
阻塞挂起:进程被写入硬盘并等待某个事件的出现。
就绪挂起:进程被写入硬盘,进入内存可直接进入就绪状态
常见的 进程调度算法
先来先服务 (FCFS,first come first served)
在所有调度算法中,最简单的是非抢占式的FCFS算法。
算法原理:进程按照它们请求CPU的顺序使用CPU.就像你买东西去排队,谁第一个排,谁就先被执行,在它执行的过程中,不会中断它。当其他人也想进入内存被执行,就要排队等着,如果在执行过程中出现一些事,他现在不想排队了,下一个排队的就补上。此时如果他又想排队了,只能站到队尾去。
算法优点:易于理解且实现简单,只需要一个队列(FIFO),且相当公平
算法缺点:比较有利于长进程,而不利于短进程,有利于CPU 繁忙的进程,而不利于I/O 繁忙的进程

最短作业优先(SJF, Shortest Job First)
短作业优先(SJF, Shortest Job First)又称为“短进程优先”SPN(Shortest Process Next);这是对FCFS算法的改进,其目标是减少平均周转时间。
算法原理:对预计执行时间短的进程优先分派处理机。通常后来的短进程不抢先正在执行的进程。
算法优点:相比FCFS 算法,该算法可改善平均周转时间和平均带权周转时间,缩短进程的等待时间,提高系统的吞吐量。
算法缺点:对长进程非常不利,可能长时间得不到执行,且未能依据进程的紧迫程度来划分执行的优先级,以及难以准确估计进程的执行时间,从而影响调度性能。

最高响应比优先法(HRRN,Highest Response Ratio Next)
最高响应比优先法(HRRN,Highest Response Ratio Next)是对FCFS方式和SJF方式的一种综合平衡。FCFS方式只考虑每个作业的等待时间而未考虑执行时间的长短,而SJF方式只考虑执行时间而未考虑等待时间的长短。因此,这两种调度算法在某些极端情况下会带来某些不便。HRN调度策略同时考虑每个作业的等待时间长短和估计需要的执行时间长短,从中选出响应比最高的作业投入执行。这样,即使是长作业,随着它等待时间的增加,W / T也就随着增加,也就有机会获得调度执行。这种算法是介于FCFS和SJF之间的一种折中算法。
算法原理:响应比R定义如下: R =(W+T)/T = 1+W/T
其中T为该作业估计需要的执行时间,W为作业在后备状态队列中的等待时间。每当要进行作业调度时,系统计算每个作业的响应比,选择其中R最大者投入执行。
算法优点:由于长作业也有机会投入运行,在同一时间内处理的作业数显然要少于SJF法,从而采用HRRN方式时其吞吐量将小于采用SJF 法时的吞吐量。
算法缺点:由于每次调度前要计算响应比,系统开销也要相应增加。

时间片轮转算法(RR,Round-Robin)
该算法采用剥夺策略。时间片轮转调度是一种最古老,最简单,最公平且使用最广的算法,又称RR调度。每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间。
算法原理:让就绪进程以FCFS 的方式按时间片轮流使用CPU 的调度方式,即将系统中所有的就绪进程按照FCFS 原则,排成一个队列,每次调度时将CPU 分派给队首进程,让其执行一个时间片,时间片的长度从几个ms 到几百ms**。在一个时间片结束时,发生时钟中断,调度程序据此暂停当前进程的执行**,将其送到就绪队列的末尾,并通过上下文切换执行当前的队首进程,进程可以未使用完一个时间片,就出让CPU(如阻塞)。
算法优点:时间片轮转调度算法的特点是简单易行、平均响应时间短。
算法缺点:不利于处理紧急作业。在时间片轮转算法中,时间片的大小对系统性能的影响很大,因此时间片的大小应选择恰当
怎样确定时间片的大小:
时间片大小的确定
1.系统对响应时间的要求
2.就绪队列中进程的数目
3.系统的处理能力

3.2 PCB
为了描述跟控制进程的运行,系统为每个进程定义了一个数据结构——进程控制块 Process Control Block,它是进程实体的一部分,是操作系统中最重要的记录型数据结构。
PCB 的作用是使一个在多道程序环境下不能独立运行的程序,成为一个能独立运行的基本单位,一个能与其它进程并发执行的进程 :
作为独立运行基本单位的标志
实现间断性的运行方式
提供进程管理所需要的信息
提供进程调度所需要的信息
实现与其他进程的同步与通信
3.2.1 PCB 信息
PCB为实现上述功能,内部包含众多信息:
进程标识符:用于唯一地标识一个进程,一个进程通常有两种标识符:
内部进程标识符:标识各个进程,每个进程都有一个并且唯一的标识符,设置内部标识符主要是为了方便系统使用。
外部进程标识符:它由创建者提供,可设置用户标识,以指示拥有该进程的用户。往往是由用户进程在访问该进程时使用。一般为了描述进程的家族关系,还应设置父进程标识及子进程标识。
处理机状态:由各种寄存器组成。包含许多信息都放在寄存器中,方便程序restart。
通用寄存器、指令计数器、程序状态字PSW、用户栈指针等信息。
进程调度信息
进程状态:指明进程的当前状态,作为进程调度和对换时的依据。
进程优先级:用于描述进程使用处理机的优先级别的一个整数,优先级高的进程应优先获得处理机
进程调度所需的其它信息:与所采用的进程调度算法有关,如进程已等待CPU的时间总和、进程已执行的时间总和等。
事件:指进程由执行状态转变为阻塞状态所等待发生的事件,即阻塞原因。
资源清单
有关内存地址空间或虚拟地址空间的信息,所打开文件的列表和所使用的 I/O 设备信息。
3.3 进程控制

进程控制是进程管理最基本的功能,主要包括创建新进程,终止已完成的进程,将发生异常的进程置于阻塞状态,将进程唤醒等。

3.3.1 进程创建

父进程可创建子进程,父进程终止后子进程也会被终止。子进程可继承父进程所有资源,子进程终止需将自己所继承的资源归还父进程。接下来看下创建的大致流程。

为新进程分配唯一进件标识号,然后创建一个空白PCB,需注意PCB数量是有限的,所以可能会创建失败。
尝试为新进程分配所需资源,如果资源不足进程会进入等待状态。
初始化PCB,有如下几个操作。
标识信息:将系统分配的标识符和父进程标识符填入新PCB
处理机状态信息:使程序计数器指向程序入口地址,使栈指针指向栈顶
处理机控制信息:将进程设为就绪/静止状态,通常设为最低优先级
如果进程调度队列能接纳新进程,就将进程插入到就绪队列,等待被调度运行。
3.3 进程控制
进程控制是进程管理最基本的功能,主要包括创建新进程,终止已完成的进程,将发生异常的进程置于阻塞状态,将进程唤醒等。
3.3.1 进程创建
父进程可创建子进程,父进程终止后子进程也会被终止。子进程可继承父进程所有资源,子进程终止需将自己所继承的资源归还父进程。接下来看下创建的大致流程。
为新进程分配唯一进件标识号,然后创建一个空白PCB,需注意PCB数量是有限的,所以可能会创建失败。
尝试为新进程分配所需资源,如果资源不足进程会进入等待状态。
初始化PCB,有如下几个操作。
标识信息:将系统分配的标识符和父进程标识符填入新PCB
处理机状态信息:使程序计数器指向程序入口地址,使栈指针指向栈顶
处理机控制信息:将进程设为就绪/静止状态,通常设为最低优先级
如果进程调度队列能接纳新进程,就将进程插入到就绪队列,等待被调度运行。
3.3.2 进程终止
进程终止情况一般分为正常结束、异常结束、外界干预三种。
正常结束
异常结束
越界错:访问的存储区越出该进程的区域
保护错:试图访问不允许访问的资源,或以不适当的方式访问(写只读)
非法指令:试图执行不存在的指令(可能是程序错误地转移到数据区,数据当成了指令)
特权指令出错:用户进程试图执行一条只允许OS执行的指令
运行超时:执行时间超过指定的最大值
等待超时:进程等待某件事超过指定的最大值
算数运算错:试图执行被禁止的运算(被0除)
I/O故障
外界干预
操作员或OS干预(死锁)
父进程请求,子进程完成父进程指定的任务时
父进程终止,所有子进程都应该结束
终止过程:

根据被终止进程的标识符,从PCB集合中检索出该PCB,读取进程状态
若处于执行状态则立即终止执行,将CPU资源分配给其他进程。
若进程有子孙进程则将其所有子孙进程终止。
全部资源还给父进程或操作系统。
该进程的PCB从所在队列/链表中移出。
3.3.3 进程阻塞

意思是该进程执行半路被阻塞,必须由某个事件进程唤醒该进程。常见的就是IO读取操作。常见阻塞时机/事件如下:

请求共享资源失败,系统无足够资源分配
等待某种操作完成
新数据尚未到达(相互合作的进程)
等待新任务
阻塞流程:

找到要被阻塞进程标识号对应的 PCB。
将该进程由运行状态转换为阻塞状态。
将该 进程PCB 插入的阻塞队列中去。
3.3.4 进程唤醒

唤醒 原语 wake up,一般和阻塞成对使用。唤醒过程如下:

从阻塞队列找到所需PCB。
PCB从阻塞队列溢出,然后变为就绪状态。
从阻塞队列溢出该PCB然后插入到就绪状态队列等待被分配CPU资源。
3.5 线程
早期操作系统是没有线程概念的,线程是后来加进来的。为啥会有线程呢?那是因为以前在多进程阶段,经常会涉及到进程之间如何通讯,如何共享数据的问题。并且进程关联到PCB的生命周期,管理起来开销较大。为了解决这个问题引入了线程。
线程是进程当中的一个执行流程。同一个进程内的多个线程之间可以共享进程的代码段、数据段、打开的文件等资源。同时每个线程又都有一套独立的寄存器和栈来确保线程的控制流是独立的。
进程有个PCB来管理,同理操作系统通过 Thread Control Block线程控制块来实现线程的管控。
3.5.2 线程优缺点
优点
一个进程中可以同时存在1~N个线程,这些线程可以并发的执行。
各个线程之间可以共享地址空间和文件等资源。
缺点
当进程中的一个线程奔溃时,会导致其所属进程的所有线程奔溃。
多线程编程,让人头大的东西。
线程执行开销小,但不利于资源的隔离管理和保护,而进程正相反。
3.5.3 进程跟线程关联

进程
是系统进行资源分配和调度的一个独立单位.
是程序的一次执行,每个进程都有自己的地址空间、内存、数据栈及其他辅助记录运行轨迹的数据
线程:
是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位
所有的线程运行在同一个进程中,共享相同的运行资源和环境
线程一般是并发执行的,使得实现了多任务的并行和数据共享。
进程线程区别:
一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
线程的划分尺度小于进程(资源比进程少),使得多线程程序的并发性高。
进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
资源分配给进程,同一进程的所有线程共享该进程的所有资源。
CPU分配资源给进程,但真正在CPU上运行的是线程。
线程不能够独立执行,必须依存在进程中。
线程快在哪儿?
线程创建的时有些资源不需要自己管理,直接从进程拿即可,线程管理寄存器跟栈的生命周期即可。
同进程内多线程共享数据,所以进程数据传输可以用zero copy技术,不需要经过内核了。
进程使用一个虚拟内存跟页表,然后多线程共用这些虚拟内存,如果同进程内两个线程进行上下文切换比进程提速很多。
3.5.4 线程实现
在前面的内存管理中说到了内核态跟用户态。相对应的线程的创建也分为用户态线程跟内核态线程。
3.5.4.1 用户态线程
在用户空间实现的线程,由用户态的线程库来完成线程的管理。操作系统按进程维度进行调度,当线程在用户态创建时应用程序在用户空间内要实现线程的创建、维护和调度。操作系统对线程的存在一无所知!操作系统只能看到进程看不到线程。所有的线程都是在用户空间实现。在操作系统看来,每一个进程只有一个线程。(使用库函数模式实现线程可以避免用户态到内核态切换)
缺点:CPU不知道线程存在,CPU的时间片切换是以进程为维度的,某个线程因为IO等操作导致线程阻塞,操作系统会阻塞整个进程,即使这个进程中其它线程还在工作。 用户态线程没法打断正在运行中的线程,除非线程主动交出CPU使用权。
3.5.4.2 内核态线程
在内核中实现的线程,是由内核管理的线程,线程对应的 TCB 在操作系统里,这样线程的创建、终止和管理都是由操作系统负责。内线程模式下一个用户线程对应一个内核线程。
优点:
一个进程中某个线程阻塞不会影响其他内核线程运行。
用户态模式一个时间片分给多个线程,内核态模式直接分配给线程的时间片增加。
缺点:
内核级线程调度开销较大。调度内核线程的代价可能和调度进程差不多昂贵,代价要比用户级线程大很多。一个线程默认栈=1M,线程多了会导致内存消耗很大。线程表是存放在操作系统固定的表格空间或者堆栈空间里,所以内核级线程的数量是有限的。
协程 Coroutines
是一种比线程更加轻量级的微线程。类比一个进程可以拥有多个线程,一个线程也可以拥有多个协程。可以简单的把协程理解成子程序调用,每个子程序都可以在一个单独的协程内执行。
协程运行在线程之上,当一个协程执行完成后,可以选择主动让出,让另一个协程运行在当前线程之上。协程并没有增加线程数量,只是在线程的基础之上通过分时复用的方式运行多个协程,而且协程的切换在用户态完成,切换的代价比线程从用户态到内核态的代价小很多,一般在Python、Go中会涉及到协程的知识,尤其是现在高性能的脚本Go。
协程注意事项:
协程运行在线程之上,并且协程调用了一个阻塞IO操作,此时操作系统并不知道协程的存在,它只知道线程,因此在协程调用阻塞IO操作时,操作系统会让线程进入阻塞状态,当前的协程和其它绑定在该线程之上的协程都会陷入阻塞而得不到调度。
因此在协程中不能调用导致线程阻塞的操作,比如打印、读取文件、Socket接口等。协程只有和异步IO结合起来才能发挥最大的威力。并且协程只有在IO密集型的任务中才会发挥作用。
4 文件管理
4.1 VFS 虚拟文件系统
文件系统在操作系统中主要负责将文件数据信息存储到磁盘中,起到持久化文件的作用。文件系统的基本组成单元就是文件,文件组成方式不同就会形成不同的文件系统。
文件系统有很多种而不同的文件系统应用到操作系统后需要提供统一的对外接口,此时用到了一个设计理念没有什么是加一层解决不了的,在用户层跟不同的文件系统之间加入一个虚拟文件系统层 Virtual File System。
虚拟文件系统层定义了一组所有文件系统都支持的数据结构和标准接口,这样程序员不需要了解文件系统的工作原理,只需要了解 VFS 提供的统一接口即可
在这里插入图片描述
日常的文件系统一般有如下三种:
磁盘文件系统:就是我们常见的EXT 2/3/4系列。
内存文件系统:数据没存储到磁盘,占用内存数据,比如/sys、/proc。进程中的一些数据映射到/proc中了。
网络文件系统:常见的网盘挂载NFS等,通过访问其他主机数据实现。
4.2 文件组成
以Linux系统为例,在Linux系统中一切皆文件,Linux文件系统会为每个文件分配索引节点 inode跟目录项directory entry来记录文件内容跟目录层次结构。
4.2.1 inode
5 输入输出管理

在这里插入图片描述
操作系统为统一管理众多的设备并且屏蔽设备之间的差异,给每个设备都安装了个小CPU叫设备控制器。每个设备控制器都知道自己对应外设的功能跟用法,并且每个设备控制器都有独有的寄存器用来跟CPU通信。
读设备寄存器值了解设备状态,是否可以接收新指令。
操作系统给设备寄存器写入一些指令可以实现发送数据、接收数据等等操作。
控制器一般分为数据寄存器、命令寄存器跟状态寄存器,CPU 通过读、写设备控制器中的寄存器来便捷的控制设备:
数据寄存器:CPU 向 I/O 设备写入需要传输的数据,比如打印what,CPU 就要先发送一个w字符给到对应的 I/O 设备。
命令寄存器:CPU 发送命令来告诉 I/O 设备要进行输入/输出操作,于是就会交给 I/O 设备去工作,任务完成后,会把状态寄存器里面的状态标记为完成。
状态寄存器:用来告诉 CPU 现在已经在工作或工作已经完成,只有状态寄存标记成已完成,CPU 才能发送下一个字符和命令。
同时输入输出设备可分为块设备跟字符设备。
块设备:用来把数据存储在固定大小的块中,每个块有自己的地址,硬盘、U盘等是常见的块设备。块设备一般数据传输较大为避免频繁IO,控制器中有个可读写等数据缓冲区。Linux操作系统为屏蔽不同块设备带来的差异引入了通用块层,通用块层是处于文件系统和磁盘驱动中间的一个块设备抽象层,主要提供如下俩功能:
向上为文件系统和应用程序,提供访问块设备的标准接口,向下把各种不同的磁盘设备抽象为统一的块设备,并在内核层面提供一个框架来管理这些设备的驱动程序。
通用层还会给文件系统和应用程序发来的 I/O进行调度,主要目的是为了提高磁盘读写的效率。
字符设备:以字符为单位发送或接收一个字符流,字符设备是不可寻址的,也没有任何寻道操作,鼠标是常见的字符设备。
CPU一般通过IO端口跟内存映射IO来跟设备的控制寄存器和数据缓冲区进行通信
IO端口:每个控制寄存器被分配一个 I/O 端口,可以通过特殊的汇编指令操作这些寄存器,比如 in/out 类似的指令。
内存映射IO:将所有控制寄存器映射到内存空间中,这样就可以像读写内存一样读写数据缓冲区。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值