操作系统:复习重点

1,进程管理

1.1,进程与线程

进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,它是系统进行资源分配和调度的一个独立单位。具有独立的内存空间、磁盘空间、I/O设备等。每个进程都有一个唯一的进程标识符(PID),可以通过操作系统的进程管理功能来管理和控制进程的执行。不同进程之间的通信通常需要通过特定的机制,例如管道、共享内存等。

线程(Thread)是进程中的一个执行单元,是线程的更细粒度的划分,每个线程也具有独立的栈、寄存器和程序计数器。不同线程共享进程的资源,包括内存空间、文件句柄、网络连接等。因此,线程之间的通信和同步相对于进程来说更加容易。线程是轻量级的,可以快速创建和销毁,适合用于处理并发任务。

【问题】引入线程的优点?

  • 提高程序的并发性:线程可以让程序同时执行多个任务,从而提高程序的并发性,使程序更加高效。

  • 提高程序的响应速度:当一个线程阻塞时,其他线程仍然可以继续执行,从而提高程序的响应速度。

  • 线程间切换代价小,进程间切换代价大。线程又称轻量级进程。进程有进程控制块,线程也有线程控制块。但线程控制块比进程控制块小得多。

  • 简化程序设计:使用线程可以将一个大的复杂任务拆分成多个小的任务,从而简化程序设计,提高代码的可维护性和可读性。

  • 支持多核处理器:多核处理器可以同时执行多个线程,从而提高系统的性能。

  • 支持并发编程:线程可以支持并发编程,使得程序员能够更容易地编写并发程序。

【父子进程】在操作系统中,父子进程是指由一个父进程派生(创建)的一个或多个子进程。这种父子进程关系通常用于多任务操作系统中,以便进行并发处理和任务管理。

  • 进程创建:父进程通过系统调用(通常是fork()系统调用)创建一个新的子进程。子进程是父进程的复制,包括代码、数据、打开的文件描述符等。
  • 进程标识:父进程和子进程有不同的进程标识符(PID)。父进程的PID通常小于子进程的PID。
  • 共享资源:父进程和子进程通常会共享一些资源,如文件描述符、内存映射区域等。这意味着它们可以在不复制资源的情况下相互通信。
  • 独立执行:父进程和子进程是相对独立的,它们有各自的执行上下文和程序计数器。子进程可以执行不同的程序,从而执行不同的任务。
  • 通信:父子进程之间可以通过进程间通信(IPC)机制来进行通信,如管道、消息队列、共享内存等。
  • 终止状态:当一个进程终止时,它的终止状态(exit status)会被传递给其父进程。父进程可以通过wait()或waitpid()等系统调用来等待子进程的终止和获取其终止状态。
  • 资源回收:操作系统通常会负责回收已终止的子进程的资源,以防止资源泄漏。
  • 例子:典型的例子是Unix和Linux操作系统中的fork()系统调用。父进程调用fork()后,会创建一个几乎与父进程相同的子进程,然后可以根据需要在子进程中执行不同的任务。

1.2,通信方式

进程的通信方式:

【管道】管道是一种半双工通信方式,通常用于父子进程之间或者具有亲缘关系的进程间通信。

【消息队列】消息队列是一种进程间通信的方式,允许不同进程通过消息传递来通信。

【共享内存】是最快的一种进程间通信方式,因为进程可以直接访问共享内存。共享内存允许多个进程访问同一块内存区域,这使得数据在进程之间的传递非常高效。需要进行同步以避免数据一致性问题。

【信号量】

  • 信号量是一种计数器,用于控制多个进程对共享资源的访问。
  • 进程可以通过操作信号量来获得对共享资源的访问权限。

【套接字】用于不同系统或网络中的进程之间的通信。套接字通过socket函数创建。

【RPC】RPC是一种高级的进程通信方式,允许一个进程调用另一个进程的过程(函数)。

线程的通信方式:

【临界区】通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。在任意时刻只允许一个线程访问共享资源,如果有多个线程试图访问共享资源,那么当有一个线程进入后,其他视图访问共享资源的线程将会被挂起,并一直等到进入临界区的线程离开,临界在被释放后,其他线程才能抢占。Java中的Synchronize关键字。

【互斥量】用于等待某个条件的发生。当条件不满足时,线程会进入等待状态,直到其他线程发出通知,告诉它条件已经满足,可以继续执行。

【信号量】信号量是一种计数器,用来控制多个线程对共享资源的访问。当线程需要访问共享资源时,它会尝试获取信号量。如果信号量的计数器大于零,线程就可以继续执行,并将信号量的计数器减一;如果信号量的计数器为零,则线程必须等待其他线程释放信号量。

【事件】事件是一种线程同步机制,可以让线程等待某个特定的条件发生。当条件满足时,事件会被触发,等待的线程就可以继续执行。

【读写锁】读写锁允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。当一个线程正在写入共享资源时,其他线程必须等待写入完成才能读取或写入。

1.3,内核线程和用户线程(用户态和核心态)

内核线程是由操作系统内核创建和管理的线程,它们运行在内核空间,拥有完全的系统权限。内核线程通常用于执行与操作系统内核相关的任务,例如处理硬件中断、管理文件系统和内存管理等。相比之下,用户线程是由应用程序创建和管理的线程,运行在用户空间,只拥有有限的系统权限。用户线程通常用于执行与应用程序相关的任务,例如处理用户输入、显示界面等。

【问题】引入用户线程的原因?

  • 可以在不支持线程的操作系统中实现。
  • 创建和销毁线程、线程切换等线程管理的代价比内核线程少很多。
  • 允许每个进程定制自己的调度算法,线程管理灵活。
  • 线程能够利用的表空间和堆栈空间比内核线程多。

【问题】用户线程的缺点?

  • 同一进程中只能同时有一个线程在运行,如果有一个线程使用了系统调用而阻塞,那么整个进程都会被挂起。
  • 页面时效也会导致整个进程都会被挂起。

核心态是操作系统的特权级别,用户态是应用程序的特权级别。

  • 用户态:当应用程序在运行时,它运行在用户态,只能访问应用程序的地址空间和有限的系统资源,例如文件和网络接口等。应用程序不能直接访问操作系统内核或硬件资源,例如中断、设备驱动和物理内存等。
  • 核心态:操作系统运行在核心态,具有完全的系统特权,可以直接访问所有的系统资源,例如内存、IO设备和中断等。操作系统的内核模式可以执行特权指令,而应用程序在用户模式下则不能执行特权指令。操作系统的内核模式通常是由处理器通过设置特殊的标志位来实现的。

用户态和核心态之间的切换是由操作系统内核完成的,通常发生在应用程序需要访问受保护资源或进行系统调用时。当应用程序需要进行系统调用时,它会触发一个软中断,将控制权转移到操作系统内核,内核会切换到核心态来处理系统调用,并在处理完成后将控制权返回给应用程序。

软中断:是计算机操作系统中的一种机制,用于实现用户空间与内核空间之间的通信和交互。软中断允许用户空间程序向内核发送请求或通知,以触发内核执行特定的操作。在操作系统中,有两种主要的中断类型:硬件中断和软件中断。硬件中断是由外部事件(如设备IO、时钟等)触发的,而软件中断则是由程序内部触发的。

  • 系统调用:用户程序通过系统调用请求内核执行特定操作,如文件读写、进程管理等。
  • 定时器和延时:用户程序可以通过软中断设置定时器或进行延时操作。
  • 信号处理:软中断用于处理信号,例如在某些事件发生时通知程序执行特定的操作。
  • 网络通信:网络协议栈中的网络数据包处理也可能使用软中断来触发内核处理数据包。

软中断的工作原理:

  • 用户空间程序通过特定的系统调用(如系统调用号)向内核发起请求。
  • 内核接收到请求后,根据系统调用号等信息确定要执行的操作。
  • 内核会在当前的执行上下文中切换到内核模式,执行与该系统调用相关的操作。
  • 执行完毕后,内核会将控制权切换回用户空间,将结果返回给用户程序。

2,内存管理

2.1,内存管理方式

【块式管理】在这种管理方式下,整个物理内存被视为一个连续的地址空间,并且每个进程都被分配一个连续的内存区域。这种方法简单易行,但是它无法支持动态内存分配,平均浪费50%的内存空间。

【页式管理】用户程序的地址空间被划分成若干个固定大小的区域,这个区域被称为“页”,相应地,内存空间也被划分为若干个物理块,页和块的大小相等。可将用户程序的任一页放在内存的任一块中,从而实现了离散分配。

  • 优点:页的大小是固定的,因此便于管理;
  • 缺点:页长与程序的逻辑大小没有任何关系。这就导致在某个时刻一个程序可能只有一部分在主存中,而另一部分则在辅存中。这不利于编程时的独立性,并给换入换出处理、存储保护和存储共享等操作造成麻烦。

【段式管理】段式虚拟存储器中,段是按照程序的逻辑结构划分的,各段的长度因程序不同而各异。使用这种方式,程序员可以把子程序、操作数和不同类型的数据和函数划分到不同的段中,如代码段、数据段、堆栈段。这种方式将用户程序地址空间分成若干个大小不等的段,每段可以定义一组相对完整的逻辑信息。存储分配时,以段为单位,段与段在内存中可以不相邻接,即实现了离散分配。

  • 优点:① 段的逻辑独立性不仅使其易于编译、管理、修改和保护,也便于多道程序共享。② 段长可以根据需要动态改变,允许自由调度,以便有效利用主存空间。③ 方便分段共享,分段保护,动态链接,动态增长。
  • 缺点:① 由于段的大小不固定,因此存储管理比较麻烦。② 会生成段内碎片,这会造成存储空间利用率降低。而且段式存储管理比页式存储管理方式需要更多的硬件支持。

分页对程序员而言是不可见的,而分段通常对程序员而言是可见的,因而分段为组织程序和数据提供了方便,但是对程序员的要求也比较高。

【段页式管理】内存首先被分为多个段,每个段再进一步划分为多个页。段提供逻辑的划分,页则实现内存的物理管理。

  • 优点:​​​​​​​既能够提供逻辑分段的灵活性,又能够避免段式管理中的外部碎片问题。
  • 缺点:管理复杂度较高,因为需要维护段表和页表两种映射关系。

2.2,虚拟内存

虚拟内存是一种利用硬盘空间模拟出的看起来像是物理内存大小无限的技术。当计算机运行程序时,操作系统会把不常用的程序或数据保存到硬盘上,腾出物理内存供其它程序使用。当需要用到被保存下来的程序时,操作系统再将它们重新调入物理内存。这样就解决了物理内存不足的问题。但是,在使用虚拟内存技术时也需要注意一些问题。例如,虚拟内存的使用会增加一定的系统开销,并且在使用交换文件时可能会导致性能瓶颈。此外,如果虚拟内存管理不当,也容易发生内存泄漏等问题。

【优点】

  • 扩大了地址空间。无论段式虚存,还是页式虚存,或是段页式虚存,寻址空间都比实存大。
  • 内存保护。每个进程运行在各自的虚拟内存地址空间,互相不能干扰对方。另外,虚存还对特定的内存地址提供写保护,可以防止代码或数据被恶意篡改。
  • 公平分配内存。采用了虚存之后,每个进程都相当于有同样大小的虚存空间。
  • 当进程需要通信时,可采用虚存共享的方式实现。

【缺点】

  • 虚存的管理需要建立很多数据结构,这些数据结构要占用额外的内存。
  • 虚拟地址到物理地址的转换,增加了指令的执行时间。
  • 页面的换入换出需要磁盘I/O,这是很耗时间的。

2.3,内存碎片

内存碎片是由于多次进行内存分配造成的,当进行内存分配时,内存格式一般为:(用户使用段)(空白段)(用户使用段),当空白段很小的时候可能不能提供给用户足够多的空间,比如夹在中间的空白段的大小为5,而用户需要的内存大小为6,这样会产生很多的间隙造成使用效率的下降,这些很小的空隙称为碎片。

  • 内碎片:分配给程序的存储空间没有用完,有一部分是程序不使用,但其他程序也没法用的空间。内碎片是处于区域内部或页面内部的存储块,占有这些区域或页面的进程并不使用这个存储块,而在进程占有这块存储块时,系统无法利用它,直到进程释放它,或进程结束时,系统才有可能利用这个存储块。
  • 外碎片:由于空间太小,小到无法给任何程序分配(不属于任何进程)的存储空间。外部碎片是出于任何已分配区域或页面外部的空闲存储块,这些存储块的总和可以满足当前申请的长度要求,但是由于它们的地址不连续或其他原因,使得系统无法满足当前申请。

内碎片和外碎片是一对矛盾体,一种特定的内存分配算法,很难同时解决好内碎片和外碎片的问题,只能根据应用特点进行取舍。

2.4,虚拟地址、逻辑地址、线性地址和物理地址

虚拟地址是指由程序产生的由段选择符和段内偏移地址组成的地址。这两部分组成的地址并没有直接访问物理内存,而是要通过分段地址的变换处理后才会对应到相应的物理内存地址。

逻辑地址是指由程序产生的段内偏移地址。有时直接把逻辑地址当成虚拟地址,两者并没有明确的界限。

线性地址是指虚拟地址到物理地址变换之间的中间层,是处理器可寻址的内存空间(称为线性地址空间)中的地址。程序代码会产生逻辑地址,或者说是段中的偏移地址,加上相应段基址就生成了一个线性地址。如果启用了分页机制,那么线性地址可以再经过变换产生物理地址。若是没有采用分页机制,那么线性地址就是物理地址。物理地址是指现在CPU外部地址总线上的寻址物理内存的地址信号,是地址变换的最终结果。

虚拟地址到物理地址的转化方法是与体系结构相关的,一般有分段与分页两种方式。以x86 CPU为例,它对于分段、分页都是支持的。内存管理单元负责从虚拟地址到物理地址的转化。逻辑地址是段标识+段内偏移量的形式,MMU通过查询段表,可以把逻辑地址转化为线性地址。如果CPU没有开启分页功能,那么线性地址就是物理地址;如果CPU开启了分页功能,那么MMU还需要查询页表来将线性地址转化为物理地址:逻辑地址(段表)→线性地址(页表)→物理地址。

2.5,Cache替换算法

数据可以存储在CPU或者内存中。CPU处理速度快,但是容量少;内存容量大,但是转交给CPU处理的速度慢。为此,需要Cache(缓存)来做一个折中。最有可能的数据先从内存调入Cache,CPU再从Cache读取数据,这样会快许多。然而,Cache中所存储的数据不足50%是有用的。CPU从Cache中读取到有用数据称为“命中”。由于主存中的块比Cache中的块多,所以当要从主存中调一个块到Cache中时,会出现该块所映射到的一组(或一个)Cache块已全部被占用的情况。此时,需要被迫腾出其中的某一块,以接纳新调入的块,这就是替换。

Cache替换算法有:RAND算法、FIFO算法、LRU算法、OPT算法和LFU算法。

  • 随机(RAND)算法。随机算法就是用随机数发生器产生一个要替换的块号,将该块替换出去,此算法简单、易于实现,而且它不考虑Cache块过去、现在及将来的使用情况。但是由于没有利用上层存储器使用的“历史信息”,没有根据访存的局部性原理,故不能提高Cache的命中率,命中率较低。
  • 先进先出(FIFO)算法。先进先出(First In First Out,FIFO)算法是将最先进入Cache的信息块替换出去。FIFO算法按调入Cache的先后决定淘汰的顺序,选择最早调入Cache的字块进行替换,它不需要记录各字块的使用情况,比较容易实现,系统开销小,其缺点是可能会把一些需要经常使用的程序块(如循环程序)也作为最早进入Cache的块替换掉,而且没有根据访存的局部性原理,故不能提高Cache的命中率。此法简单、方便,利用了主存的“历史信息”,但并不能说最先进入的就不经常使用,其缺点是不能正确反映程序局部性原理,命中率不高,可能出现一种异常现象。
  • 近期最少使用(LRU)算法。近期最少使用(Least Recently Used,LRU)算法是将近期最少使用的Cache中的信息块替换出去。LRU算法是依据各块使用的情况,总是选择最近最少使用的块被替换。这种方法虽然比较好地反映了程序局部性规律,但是这种替换方法需要随时记录Cache中各块的使用情况,以便确定哪个块是近期最少使用的块。LRU算法相对合理,但实现起来比较复杂,系统开销较大。通常需要对每一块设置一个称为计数器的硬件或软件模块,用以记录其被使用的情况。计数器方法:① 被调入或者被替换的块,其计数器清“0”,而其他的计数器则加“1”。② 当访问命中时,所有块的计数值与命中块的计数值要进行比较,如果计数值小于命中块的计数值,那么该块的计数值加“1”;如果块的计数值大于命中块的计数值,那么数值不变。最后将命中块的计数器清为“0”。③ 需要替换时,则选择计数值最大的块被替换。
  • 最优替换(OPT)算法。前面介绍的几种页面替换算法主要是以主存储器中页面调度情况的历史信息为依据的,它假设将来主存储器中的页面调度情况与过去一段时间内主存储器中的页面调度情况是相同的,显然,这种假设不总是正确的。最好的算法应该是选择将来最久不被访问的页面作为被替换的页面,这种替换算法的命中率一定是最高的,它就是最优替换算法。使用最优替换(OPTimal replacement,OPT)算法时必须先执行一次程序,统计Cache的替换情况。有了这样的先验信息,在第二次执行该程序时便可以用最有效的方式来替换,以达到最优的目的。要实现OPT算法,唯一的办法是让程序先执行一遍,记录下实际的页地址的使用情况。根据这个页地址的使用情况才能找出当前要被替换的页面。显然,这样做是不现实的。因此,OPT算法只是一种理想化的算法,然而它也是一种很有用的算法。实际上,经常把这种算法用来作为评价其他页面替换算法好坏的标准。在其他条件相同的情况下,哪一种页面替换算法的命中率与OPT算法最接近,那么它就是一种比较好的页面替换算法。
  • 最不经常使用淘汰(LFU)算法。最不经常使用淘汰(Least Frequently Used,LFU)算法淘汰一段时间内,使用次数最少的页面。显然,这是一种非常合理的算法,因为到目前为止最少使用的页面,很可能也是将来最少访问的页面。该算法既充分利用了主存中页面调度情况的历史信息,又正确反映了程序的局部性。但是,这种算法实现起来非常困难,它要为每个页面设置一个很长的计数器,并且要选择一个固定的时钟为每个计数器定时计数。在选择被替换页面时,要从所有计数器中找出一个计数值最大的计数器。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

燕双嘤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值