操作系统八股1
操作系统八股
对操作系统有一个更加全面的认识,操作系统八股文专项突破!!!
什么是操作系统(Operating System,OS)
操作系统是计算机系统中管理硬件和软件资源的中间层系统,位于用户程序与计算机硬件之间,起到桥梁的作用。
- 作用:
- 屏蔽硬件细节,简化用户操作
- 管理资源(CPU、内存、设备、文件等)
- 为用户和程序提供统一、简洁、抽象的接口
- 常见操作系统举例:
- Windows
- Linux
- macOS
- Android、iOS(移动设备)
操作系统的主要功能
操作系统有以下几个核心功能模块,每一项都至关重要:
1. 进程管理
- 进程是程序的运行实例,是资源分配的基本单位。
- 操作系统负责:
- 创建与终止进程
- 分配和回收进程所需资源(如CPU时间、内存)
- 进行进程调度(决定哪个进程先运行)
- 维护进程状态与进程控制块(PCB)
2. 内存管理
- 任务:
- 分配内存给正在运行的程序
- 跟踪内存使用情况,防止越界访问
- 在进程终止时回收所占内存
- 支持虚拟内存技术,提供比实际内存更大的地址空间
3. 文件管理
- 文件是操作系统中用于存储数据的抽象形式
- 操作系统提供:
- 创建、删除、读写文件的接口
- 文件目录结构管理(如树状目录)
- 权限管理(谁可以访问什么文件)
- 持久化存储支持(通常在磁盘上)
4. 设备管理
- 控制和协调硬件设备的使用
- 通过设备驱动程序(Driver)来实现对设备的操作
- 管理内容包括:
- 输入设备:键盘、鼠标、扫描仪等
- 输出设备:显示器、打印机、音箱等
- 存储设备:硬盘、U盘、光盘等
- 任务包括缓冲、排队、错误处理等
5. 用户接口管理(可选扩展)
- 为用户提供操作计算机的接口,包括:
- 命令行界面(CLI):如 Linux shell
- 图形用户界面(GUI):如 Windows 桌面
什么是内核(Kernel)
📌 定义:
内核是操作系统中最核心的部分,它是一个控制计算机硬件和软件资源的程序,负责操作系统的基本功能。
📌 特点:
- 是 操作系统的心脏,管理所有系统资源
- 运行在内核态(Kernel Mode),拥有最高权限
- 用户程序不能直接操作内核,必须通过系统调用间接请求服务
📌 内核的核心功能包括:
- 进程调度与管理
- 内存管理
- 文件系统操作
- 设备驱动程序接口
- 系统调用接口
什么是用户态(User Mode)和内核态(Kernel Mode)
📌 用户态与内核态的基本区别:
属性 | 用户态(User Mode) | 内核态(Kernel Mode) |
---|---|---|
权限等级 | 低 | 高 |
可访问范围 | 只能访问用户空间 | 可以访问内核空间和所有硬件资源 |
应用程序行为 | 执行普通计算,如变量运算、函数调用等 | 执行操作系统代码,如调度、内存分配等 |
稳定性 | 出错仅影响当前进程 | 出错可能导致整个系统崩溃 |
示例 | 用户运行的应用程序(如浏览器、编辑器等) | 系统调用、驱动程序执行过程 |
📌 为什么需要划分用户态和内核态?
- 系统安全性:防止普通程序随意操作内核或硬件
- 系统稳定性:用户程序崩溃不会影响整个操作系统
- 资源隔离与保护:防止非法访问其他进程或系统资源
📌 状态切换:从用户态到内核态
- 系统调用(System Call) 当用户程序需要操作硬件或请求操作系统服务(如读文件、申请内存),必须通过系统调用切换到内核态。
- 中断/异常处理 例如键盘输入、定时器中断、除零异常,也会使 CPU 进入内核态处理。
- 完成任务后,系统返回用户态,继续执行用户程序。
📝 举例说明:
1 | // C语言中read()函数 |
📌 图示辅助(文字版):
1 | +--------------------+ +---------------------+ |
用户态与内核态是如何切换的?
📌 一、切换的基本概念
在现代操作系统中,为了保护系统资源、确保稳定性与安全性,用户程序不能直接操作硬件资源或内核数据结构,必须通过系统调用(System Call)进入内核态。
✅ 切换方式本质上是:触发一次特权级转换,由 CPU 控制权限从用户模式(Ring 3)切换到内核模式(Ring 0)。
📌 二、切换的触发条件
用户态切换到内核态,通常有以下几种情况:
触发条件 | 描述说明 |
---|---|
系统调用 | 用户程序请求 OS 服务,如
read() 、write() |
中断 | 外部设备(如键盘、鼠标)产生中断 |
异常 | 程序运行出错,如除以零、非法内存访问等 |
📌 三、系统调用过程(详细步骤)
以 Linux 为例,用户程序调用 read()
函数读取文件的过程:
➤ 步骤
1:用户程序调用库函数(如 C 的 read()
)
- 位于用户空间,调用的是标准 C 库中的封装函数。
➤
步骤 2:发起系统调用指令(如 x86 架构中的 int 0x80
或
syscall
)
- CPU 进入内核态(特权级提升),切换到内核栈,跳转到内核空间执行。
➤ 步骤
3:操作系统内核根据系统调用号查找服务例程(如
sys_read
)
- 执行内核代码,访问文件系统、硬件设备、内存等。
➤ 步骤
4:内核执行完毕后,通过 ret_from_syscall
等机制返回
- CPU 恢复原来的用户态上下文,返回结果给用户程序。
📌 四、从内核态返回用户态
- 当系统调用完成,或中断处理完成后:
- 内核将结果保存到用户进程可访问的位置;
- 恢复原来的用户态寄存器值、程序计数器等;
- CPU 将控制权交还用户程序,回到用户态继续执行。
📌 五、图示流程(文字版)
1 | [用户态] |
📌 六、常见系统调用示例(Linux)
功能分类 | 系统调用 |
---|---|
文件操作 | open() , read() , write() ,
close() |
进程控制 | fork() , exec() , exit() ,
wait() |
内存管理 | brk() , mmap() , munmap() |
设备管理 | ioctl() , read() , write() |
并发(Concurrency)与并行(Parallelism)
📌 并发(Concurrency)
定义:
- 并发是指在一段时间内多个任务“交替”进行。
- 在单核 CPU 上,通过时间片轮转快速切换任务,实现“多个任务同时执行”的假象。
关键点:
- 同一时间点,只能执行一个任务。
- 多个任务“你上完我上”,表现为“同时进行”,但实际是轮流执行。
- 实现方式:上下文切换 + 时间片分配
举例:
你一个人炒两个菜,一会炒A菜,一会炒B菜,交替操作,虽然只有一个锅,但你操作得快,看起来像在“同时炒”。
📌 并行(Parallelism)
定义:
- 并行是指在同一时刻多个任务真正地同时进行。
- 必须依赖多核/多CPU 资源,每个核/处理器负责一个任务。
关键点:
- 同一时间点,多个任务同时执行。
- 是物理上的并行执行,不依赖时间片切换。
举例:
你和朋友各炒一个菜,用两个锅、两个灶台,同一时刻炒两个菜,这是真正的“同时炒”。
📌 对比总结:
特性 | 并发(Concurrency) | 并行(Parallelism) |
---|---|---|
是否同时运行 | 看起来是,实质轮流运行(单核) | 真正地同时运行(多核) |
处理器需求 | 单核即可 | 多核或多 CPU |
关注点 | 如何调度多个任务 | 如何提高多任务执行效率 |
示例 | 单人轮流做两件事 | 两人同时做两件事 |
什么是进程上下文切换(Process Context Switch)
📌 定义:
进程上下文切换是指操作系统在多任务环境下,将 CPU 从一个进程切换到另一个进程的过程。
- 由于 CPU 一次只能处理一个进程(单核),因此需要定时切换,让多个进程“共享” CPU。
- 每次切换时,OS 都要保存和恢复进程的状态信息,这一过程叫做“上下文切换”。
📌 上下文(Context)是什么?
“上下文”指的是进程在执行过程中的所有状态信息,包括:
- 程序计数器(PC)
- CPU 寄存器
- 堆栈指针
- 内存映射信息
- 文件描述符等
📌 上下文切换的步骤(详细)
- 保存当前进程的上下文
- 操作系统记录当前进程的寄存器值、程序计数器、内存状态等信息,并存入 PCB(进程控制块)中。
- 选择下一个要运行的进程
- 调度器根据调度算法(如时间片轮转、优先级等)选出下一个进程。
- 恢复新进程的上下文
- 将下一个进程的 PCB 中保存的上下文信息加载到 CPU 中。
- 切换完成,开始执行新进程
📌 上下文切换的代价
- 开销较大:涉及寄存器存取、缓存失效(cache miss)、TLB刷新等
- 频繁切换会降低效率
- 为此,操作系统需要合理调度、控制切换频率
📌 举例说明
假设有两个进程 A 和 B 在执行:
1 | 时间片 1: |
📌 图示流程(文字版)
1 | [进程 A 运行中] |
进程的状态(Process States)
一个进程在运行过程中,通常会经历以下几种状态:
📌 主要的三种状态
状态名 | 英文名 | 含义说明 |
---|---|---|
运行(运行中) | Running | 正在使用 CPU 执行指令,系统中同时最多只有一个进程处于运行状态(在单核 CPU 情况下) |
就绪 | Ready | 进程已准备好运行,但因 CPU 被占用而暂时不能执行,等待调度 |
阻塞(等待) | Blocked / Waiting | 进程因等待某事件(如 I/O 完成)而暂停执行,即使此时有 CPU 可用也无法执行 |
📌 其他两种补充状态(形成五状态模型)
状态名 | 英文名 | 含义说明 |
---|---|---|
创建 | New | 进程正在被系统创建,还未进入就绪队列 |
结束 | Exit / Terminated | 进程完成或被终止,系统正在清理它占用的资源 |
📌 状态转换图
僵尸进程(Zombie Process)
📌 定义
- 僵尸进程是已经终止但其进程描述信息(如 PID、状态码)仍保存在进程表中的进程。
- 通常发生在子进程结束但父进程未回收子进程资源的情况下。
📌 产生原因
- 每个子进程终止时,会向其父进程发送
SIGCHLD
信号,并留下一个退出状态。 - 父进程应该通过
wait()
或waitpid()
系统调用回收子进程资源(即读取退出状态)。 - 如果父进程没有处理这个信号,子进程的资源(PCB)就不会释放,从而形成僵尸进程。
📌 僵尸进程的危害
- 僵尸进程不会继续占用 CPU 和内存,但会占用进程表项(进程号 PID)。
- 如果大量僵尸进程长期存在,会导致系统不能创建新进程(进程表项耗尽)。
📌 如何避免或清理僵尸进程
- 父进程调用
wait()
或waitpid()
:- 正确方式是让父进程在适当时机主动回收子进程资源。
- 使用信号处理函数处理
SIGCHLD
:- 在父进程中注册信号处理函数自动处理子进程退出事件。
- 让子进程由 init 进程接管:
- 如果父进程异常退出,孤儿进程会被
init
(PID=1)接管,init
会自动清理。
- 如果父进程异常退出,孤儿进程会被
📌 图示说明(文字描述)
1 | [子进程运行中] |
孤儿进程(Orphan Process)
📌 定义
- 孤儿进程是指其父进程已经终止(退出),而子进程仍在继续运行的进程。
- 在 Unix/Linux 系统中,如果一个进程变成孤儿,系统会自动将它的父进程指向 init 进程(PID=1)。
- init 进程会负责回收孤儿进程结束后的资源,防止它们变成僵尸进程。
📌 示例说明
1 | 父进程 A |
📌 与僵尸进程的区别对比
特性 | 孤儿进程 | 僵尸进程 |
---|---|---|
定义 | 父进程终止,子进程仍在运行 | 子进程终止,父进程未回收其资源 |
状态 | 仍在运行 | 已终止,但进程表项未清理 |
是否会被清理 | 会,由 init 进程自动收养和清理 | 不会自动清理,需父进程主动调用 wait() |
是否有危害 | 无危害 | 如果积累过多,会耗尽系统进程表资源 |
📌 为什么孤儿进程不会造成危害?
- 孤儿进程的退出状态会被 init 进程及时回收;
- init 是系统第一个进程,负责托管系统中失去父进程的孤立子进程;
- 不会造成僵尸进程堆积,也不会浪费系统资源。
📌 延伸知识:孤儿进程的创建过程(举例)
1 |
|
运行效果:
- 父进程立即退出;
- 子进程延迟运行,成为孤儿,被 init 接管。
📌 总结口诀
**“父亡子存是孤儿,init 养育不成灾。”
进程调度算法(Process Scheduling Algorithms)
进程调度算法决定了哪个进程可以在何时使用 CPU,是多道程序设计的核心机制之一,目标包括提高 CPU 利用率、提高系统吞吐量、减少平均等待时间等。
① 先来先服务(FCFS,First-Come First-Served)
- 原理:按进程到达就绪队列的时间顺序进行调度。
- 特点:
- 简单、易于实现;
- 非抢占式;
- 容易导致“长进程堵塞短进程”(即“饥饿”现象)。
📌 举例:进程 A(需要 10s),B(需要 2s),A 先到,B 需等 A 执行完再执行。
② 短作业优先(SJF,Shortest Job First)
- 原理:选择估计执行时间最短的进程优先执行。
- 特点:
- 最小化平均等待时间;
- 非抢占式(也有抢占式变种,见 SRTF);
- 需要准确预测执行时间,现实中难以实现;
- 容易导致长作业饿死。
③ 优先级调度(Priority Scheduling)
- 原理:根据进程的优先级调度,优先级高者先运行。
- 实现方式:
- 非抢占式:当前进程运行完才切换;
- 抢占式:新到高优先级进程可中断当前执行。
- 特点:
- 灵活;
- 如果不处理“优先级反转”,低优先级进程可能长期得不到执行;
- 可配合老化技术动态调整优先级避免饿死。
④ 时间片轮转(Round Robin, RR)
- 原理:给每个进程分配一个固定的时间片,时间片耗尽就换下一个进程。
- 特点:
- 抢占式调度;
- 公平性好,适合交互式系统;
- 时间片大小影响性能:
- 太小 ⇒ 频繁切换、开销大;
- 太大 ⇒ 类似 FCFS,响应时间长。
⑤ 最短剩余时间优先(SRTF, Shortest Remaining Time First)
- 原理:抢占式的 SJF。选择剩余执行时间最短的进程运行。
- 特点:
- 每次新进程进入,都会检查是否比当前进程短;
- 平均等待时间最小;
- 预测执行时间困难;
- 容易导致长作业饿死。
⑥ 多级反馈队列(Multilevel Feedback Queue)
- 原理:结合时间片轮转和优先级调度思想:
- 设置多个就绪队列(如 Q1、Q2、Q3),每个队列时间片长度逐级变长;
- 新进程从高优先级队列开始运行;
- 若没在该队列完成 ⇒ 下降到下一队列;
- 高优先级队列有更高调度权。
- 特点:
- 动态调整进程优先级,适应进程类型;
- 避免长作业频繁切换;
- 实现复杂。
📊 总结对比表
调度算法 | 抢占性 | 是否需要估算执行时间 | 优点 | 缺点 |
---|---|---|---|---|
FCFS | 否 | 否 | 简单,易于实现 | 可能导致短作业等待时间过长 |
SJF | 否 | 是 | 平均等待时间最短 | 难以准确预估时间,易造成长作业饥饿 |
优先级调度 | 可抢占 | 否 | 灵活、可调整策略 | 可能发生优先级反转与进程饿死 |
时间片轮转 | 是 | 否 | 公平、适合交互系统 | 时间片设定不当会影响性能 |
SRTF | 是 | 是 | 最短平均等待时间 | 同样难以估算时间,饿死风险高 |
多级反馈队列 | 是 | 否 | 动态适应不同进程,效率高 | 实现复杂 |
进程间通信(InterProcess Communication, IPC)
一、IPC 的六种主要方式
通信方式 | 是否支持无亲缘关系 | 数据流向 | 通信效率 | 特点或用途 |
---|---|---|---|---|
管道(Pipe) | 匿名管道:否命名管道:是 | 单向(默认) | 较低 | 简单实现、适用于父子进程通信 |
信号(Signal) | 是 | 单向通知 | 较低 | 通知机制,适用于异步事件处理 |
消息队列 | 是 | 双向可控 | 中等 | 有类型、有序、可靠,适合结构化消息传递 |
共享内存 | 是 | 双向 | 最快 | 直接共享内存,需同步机制配合 |
信号量(Semaphore) | 是 | 无直接数据 | 较高 | 用于同步与互斥,保护共享资源 |
套接字(Socket) | 是(跨主机) | 双向 | 较高 | 支持网络通信,适用于分布式系统 |
二、各通信方式详细说明
1. 管道 Pipe
- 📌 本质:内核中的一段缓存区。
- 📥 写入端 → 管道 → 读取端(FIFO)。
- 分为:
- 匿名管道:
pipe()
系统调用,只支持父子进程通信。 - 命名管道(FIFO):
mkfifo()
,支持无亲缘关系进程通信。
- 匿名管道:
- ⚠️ 缺点:只支持单向通信,效率低,不能用于频繁数据交换。
✅ 示例代码(匿名管道):
1 | int pipefd[2]; |
2. 信号 Signal
- 📌 是一种“事件通知机制”,用来告诉进程“发生了某个事件”。
- ⏰ 属于异步通信。
- 常用信号:
SIGINT
:Ctrl+C 产生,终止程序。SIGTERM
:请求终止进程(可被捕获)。SIGKILL
:强制终止进程(不可被阻塞/捕获)。SIGHUP
:终端挂断。
- 🧠 类似“手机短消息”,不适合传输数据,仅适合通知。
3. 消息队列 Message Queue
- 📌 是内核维护的消息链表,进程可以向队列中发送/接收消息。
- 🧷 特点:
- 支持消息分类。
- 有消息长度上限。
- 用户态和内核态之间有数据拷贝(性能影响)。
- 📦 优点:
- 支持无亲缘关系进程通信。
- 安全性高、可靠性好。
4. 共享内存 Shared Memory
- 📌 允许多个进程访问同一段物理内存。
- ⚡ 是最快的通信方式,因为不需要内核中转。
- 📌
系统调用:
shmget()
、shmat()
、shmdt()
。 - ⚠️ 缺点:需要额外的同步机制(如信号量)以避免竞争条件和数据错乱。
5. 信号量 Semaphore
- 📌 是一种“进程同步与互斥”的控制手段。
- 🧠 本质是一个整型计数器。
- 常用操作:
P()
(wait):尝试获取资源,计数器减1。V()
(signal):释放资源,计数器加1。
- ✅ 主要用于:控制临界区、实现互斥锁、资源数量管理。
- 💡 类比:交通红绿灯。
6. 套接字 Socket
- 📌 是网络通信的端点。
- 可用于:
- 同一主机内进程通信(UNIX socket)。
- 不同主机进程通信(TCP/IP socket)。
- 🛜 通常用于客户端-服务器(C/S)模式通信。
- 💡 类似 Java 的
Socket
类,支持双向、可靠连接。
三、总结对比图(记忆推荐)
类别 | 是否跨主机 | 是否亲缘限制 | 适合传递数据量 | 是否双向 | 通信速度 | 用途示意 |
---|---|---|---|---|---|---|
匿名管道 | 否 | 有 | 小 | 否 | 慢 | 父子进程传一句话 |
命名管道 | 否 | 无 | 小 | 否 | 慢 | 两个程序用文件通信 |
信号 | 是(仅通知) | 无 | 无 | 否 | 慢 | 异常处理/中断通知 |
消息队列 | 否 | 无 | 中等 | 是 | 中等 | 顺序传数据、分类型 |
共享内存 | 否 | 无 | 大 | 是 | 最快 | 大量数据共享(图像) |
信号量 | 否 | 无 | 无 | 无 | 快 | 控制共享内存访问 |
套接字 | 是 | 无 | 大 | 是 | 中等 | 网络程序/分布式系统 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Totoroの旅!
评论