下面从概念、区别、联系、执行流程、常见误区几个层面,系统讲清楚「中断」与「系统调用」。
一、什么是中断(Interrupt)
1. 基本定义
中断是 CPU 对异步事件的一种响应机制:
CPU 在执行当前程序时,被某个外部或内部事件“打断”,转去执行一段预先设定好的代码(中断处理程序),处理完后再回来继续执行原来的程序。
一句话:中断 = CPU 被打断 → 执行中断服务程序 → 恢复原执行流
2. 中断的分类(按来源)
| 分类 | 来源 | 特点 | 示例 |
|---|---|---|---|
| 外部中断(硬件中断) | 外设 / 中断控制器 | 异步、随机 | 键盘敲击、网卡收包、定时器中断 |
| 内部中断(异常) | CPU 内部 | 同步、由当前指令触发 | 除零错误、缺页异常、非法指令 |
| 软中断(软件中断) | 程序主动触发 | 同步 | int 0x80(Linux)、syscall |
注意:不同教材对“软中断”的定义略有差异,有些把“系统调用”单独列一类。
3. 中断的核心作用
- 实现 I/O 并发(CPU 不用死等外设)
- 实现 抢占式调度
- 实现 异常处理
- 支撑 系统调用
二、什么是系统调用(System Call)
1. 基本定义
系统调用是操作系统提供给用户程序的受控接口,用于请求内核服务。
因为用户态程序:
- 不能直接访问硬件
- 不能执行特权指令
- 不能随意修改内核数据
所以必须通过系统调用,进入内核态,由内核代劳。
一句话:系统调用 = 用户程序“合法地”请求内核帮忙
2. 常见系统调用举例
- 文件:
open / read / write / close - 进程:
fork / exec / exit - 内存:
brk / mmap - 通信:
socket / send / recv
三、中断与系统调用的关系(重点)
1. 系统调用本质上是一种“特殊的中断”
| 对比项 | 普通中断 | 系统调用 |
|---|---|---|
| 触发方式 | 硬件 / 异常 | 程序主动执行特定指令 |
| 同步/异步 | 异步 | 同步 |
| 是否特权 | 自动进入内核态 | 自动进入内核态 |
| 实现机制 | 中断向量表 IDT | 同样走 IDT |
| 本质 | 硬件机制 | 基于中断机制的软件接口 |
👉 系统调用通常是通过“软中断”或专用指令实现的,底层仍然依赖中断机制。
2. 现代系统的两种实现方式
(1)传统方式:int 0x80(x86 32位)
mov eax, 1 ; sys_exit
int 0x80
int触发软中断- CPU 查 IDT → 跳转到系统调用入口
- 陷入内核态
(2)现代方式:syscall 指令(x86_64)
- 专用指令,更快
- 不再走传统中断流程
- 但语义上仍然是“用户态 → 内核态的受控切换”
四、系统调用的完整执行流程(以 Linux 为例)
以 read(fd, buf, size) 为例:
-
用户态准备参数
- 系统调用号放入寄存器(eax/rax)
- 参数放入约定寄存器
-
执行 syscall / int 0x80
- CPU 切换到内核栈
- 保存用户态上下文(rip, rsp, rflags…)
- 跳转到内核系统调用入口
-
内核处理
- 查系统调用表
- 权限检查
- 执行
sys_read - 可能阻塞(等待 I/O)
-
返回用户态
- 恢复寄存器
- 返回结果(通常放在 rax)
- 回到原用户程序继续执行
五、为什么系统调用“慢”?
系统调用比普通函数调用慢,原因包括:
- 特权级切换(用户态 ↔ 内核态)
- 上下文保存/恢复
- TLB / Cache 失效
- 可能触发调度或阻塞
这也是为什么频繁调用 read/write 会慢,于是有了:
readv/writevmmap- 用户态缓冲(stdio)
六、常见面试 / 考试易错点
❌ 错误理解
- “系统调用不是中断”
- “只有硬件才能产生中断”
- “系统调用是函数调用”
✅ 正确理解
- 系统调用依赖中断/陷阱机制
- 它是同步异常 / 软中断
- 是用户态到内核态的唯一合法入口之一
七、一张总结对照表
| 项目 | 中断 | 系统调用 |
|---|---|---|
| 本质 | CPU 响应事件的机制 | 请求内核服务的接口 |
| 触发源 | 硬件 / 异常 / 软件 | 程序主动 |
| 是否同步 | 大多异步 | 同步 |
| 是否特权 | 是 | 是 |
| 是否可预测 | 否 | 是 |
| 底层机制 | IDT + 中断向量 | IDT / syscall |
八、一句话总结
中断是 CPU 的机制,系统调用是对该机制的典型应用;
没有中断(或等价机制),就没有现代操作系统的系统调用。