Open rrain7 opened 2 years ago
死锁的四个必要条件是什么
死锁的四个必要条件是什么
人们都希望同时运行多个程序, 比如在工作的同时也希望听听音乐, 摸摸鱼. 对于现代操作系统来说, CPU是有限的, 而希望运行的应用数量大于CPU的数量. 操作系统通过虚拟化CPU来提供这种假象. 通过让一个进程只运行一个时间片, 然后切换到其他进程, 操作系统提供了存在多个虚拟CPU的假象. 操作系统为正在运行的程序提供的抽象, 就是所谓的进程. 那么构成进程的是什么呢?
经典的观点是一个程序只有一个执行点(一个程序计数器, 用来存放要执行的指令), 但多线程程序会有多个执行点(多个程序计数器, 每个都用于取指令和执行). 每个线程类似与独立的进程, 只有一点区别: 它们共享地址空间, 从而能够访问相同的数据. 单个线程的状态与进程的状态非常类似, 线程有一个程序计数器, 记录从哪里获得指令, 每个线程都有自己的一组用于计算的寄存器. 若有两个线程运行在一个处理器上, 从运行一个线程T1 切换到另一个线程T2 必定发生上下文切换. 与进程上下文切换类似, 进程的上下文切换, 我们将状态保存在进程控制块, 现在需要一个或多个线程控制块保存每个线程的状态. 但是有一点区别就是: 线程的地址空间保持不变. 进程和线程之间的另一个主要区别在于 栈. 简单的传统进程地址空间中只有一个栈, 在多线程的进程中, 每个线程独立运行, 都拥有自己的栈.
死锁的四个必要条件是什么
关于锁, 我们如何实现锁呢? 在实现之前, 先看看如何评价一种锁的实现效果. 一些标准:
关于锁🔒
锁并不是并发程序设计所需要的唯一原语 具体来说, 很多情况下, 线程需要检查某一个条件满足后, 才会运行 如何等待一个条件
多线程程序中, 一个线程等待某些条件是很常见的, 简单的方案是自旋直到条件满足, 这个是极其低效的, 甚至某些情况下是错误的, 那么, 线程如何等待一个条件?
操作系统提供对物理内存进行抽象 -- 地址空间
一个进程的 地址空间 包含运行的程序的所有内存状态。 比如:
当我们描述「地址空间」时,所描述的是操作系统提供给运行程序的抽象, 程序不在物理地址 0~16 k 的内存中,而是加载在任意的物理地址。
操作系统如何在单一的物理内存上为多个运行的进程(所有进程共享内存)构建一个私有的、可能 很大的地址空间的抽象?
虚拟内存系统的一个目标是:透明
透明指的是:操作系统提供的假象不应该被应用程序看破。
另一个目标是:效率 第三个目标是:保护
操作系统应确保进程受到保护(protect),不会受其他进程影响,操作系统本身也不会受进程影响。
基于硬件的地址转换:利用地址转换,硬件将指令中的虚拟地址转换为数据实际存储的物理地址。
每次内存引用,硬件都会进行地址转换,将运行应用的内存引用重定位到为实际的物理地址。
仅仅依靠于硬件不足以实现 虚拟内存,它只提供了底层机制来提高效率,操作系统必须在关键时刻介入,设置好硬件完成地址转换。
同样,所有这些工作都是为了创造一种美丽的假象:每个程序都拥有私有的内存,那里存放着它自己的代码和数据。虚拟现实的背后是丑陋的物理事实:许多程序其实是在同一时间共享着内存,就像CPU(或多个CPU)在不同的程序间切换运行。通过虚拟化,操作系统(在硬件的帮助下)将丑陋的机器现实转化成一种有用的、强大的、易于使用的抽象。
基址(base) + 界限(bound)机制 具体来说:每个 CPU 需要两个硬件寄存器,基址寄存器+界限寄存器
这组基址和界限寄存器,让我们能够将地址空间放在物理内存的任何位置,同时又能确保进程只能访问自己的地址空间。
进程中使用的内存引用是 虚拟地址 硬件会将 虚拟地址 + 基址寄存器的内容,得到物理地址,再发送给内存系统。
界限寄存器提供了访问保护,确保进程产生的所有地址都在进程的地址“界限”中。
在一些关键的时刻, 操作系统需要介入,以实现基址和界限方式的虚拟内存
一般来说,操作系统正确设置硬件后,就任凭进程直接在 CPU 上执行,只有进程行为不端或者中断的时候才介入。
上述 基址+界限 的方式,可能在堆和栈之前存在很大的空闲区域,这样的虚拟内存很浪费。另外,如果剩余物理内存无法提供连续区域来放置完整的地址空间,进程便无法运行。
这样的虚拟内存显然不够灵活,怎么支持大地址空间?
引入不止一个 基址+界限寄存器 对, 而是给地址空间每个逻辑段一对。
分段的机制使得操作系统能够将不同的段放到不同的物理内存区域,从而避免了虚拟地址空间中的未使用部分占用物理内存。
==todo==
操作系统八股文 (想写一篇脱离低级趣味的八股文, 555555555)