操作系统
Operating System
用进程隔离程序,用虚拟内存欺骗每个程序'独占整台机器'。
操作系统(Operating System)是管理硬件资源、为应用程序提供服务的系统软件。核心抽象包括:进程(Process,运行中的程序实例,拥有独立地址空间)、线程(Thread,进程内的执行单元,共享地址空间)、虚拟内存(Virtual Memory,通过页表将虚拟地址映射到物理地址,使每个进程'看到'独立的 4GB/256TB 地址空间)、文件系统(File System,将磁盘组织为文件和目录的层次结构)、系统调用(System Call,应用程序请求内核服务的接口,如 read/write/fork/exec)。操作系统运行在内核态(Kernel Mode),拥有最高权限;应用程序运行在用户态(User Mode),权限受限。上下文切换(Context Switch)在进程/线程间切换时保存和恢复状态。
没有操作系统,每个程序都需要直接管理硬件(内存分配、磁盘 IO、网络),既复杂又容易冲突。操作系统通过抽象和隔离,使程序员可以专注于业务逻辑,而不必关心底层硬件细节。虚拟内存提供内存保护(防止进程互相干扰)和内存扩展(通过分页和交换,使程序可以使用比物理内存更大的地址空间)。进程隔离确保一个程序的崩溃不会影响其他程序。文件系统提供持久化存储的统一接口。
程序员通过系统调用(或标准库封装)与操作系统交互。POSIX 标准定义了 Unix/Linux 系统调用接口(fork/exec/read/write/mmap 等)。理解操作系统有助于理解:为什么 fork 后子进程复制父进程的地址空间(写时复制优化);为什么线程切换比进程切换快(共享地址空间);为什么 mmap 可以加速文件 IO(避免内核态到用户态的数据拷贝);为什么信号量/互斥锁是并发编程的基础(同步对共享资源的访问)。
Bottom-up:由下层如何构建
本层建立在以下层级之上:
Top-down:向上暴露什么接口
Programmer View:程序员视角
我能操作吗?
通过系统调用(syscall)或标准库(libc)间接操作。POSIX API 提供跨平台接口。Linux 特有功能可通过 ioctl、/proc、/sys 访问。
成本模型
| 指标 | 量级 | 备注 |
|---|---|---|
| 进程创建(fork) | ~10-100 μs | 写时复制优化,实际复制很少 |
| 线程创建 | ~1-10 μs | 比进程快,共享地址空间 |
| 上下文切换 | ~1-10 μs | 进程切换比线程切换慢(需要切换页表) |
| 系统调用 | ~1000-2000 周期 | 用户态到内核态切换 |
| 页面错误(Page Fault) | ~10 ms(磁盘 IO) | 按需分页,首次访问触发 |
常见陷阱
- !死锁(Deadlock):多个线程互相持有对方需要的锁,导致永久阻塞。避免策略:锁排序、超时、死锁检测
- !内存泄漏:程序分配内存但不释放,长期运行后耗尽内存。工具:valgrind、AddressSanitizer
- !信号处理:信号处理函数应尽量减少工作(设置标志位),避免在信号处理函数中调用非异步安全函数(如 malloc、printf)