IPC、调度与虚拟内存边界 / IPC, Scheduling, and Virtual Memory Boundaries
1. 为什么 IPC 是边界设计
进程之间默认隔离。一个进程的指针在另一个进程里没有意义;一个进程崩溃不应直接破坏另一个进程的地址空间。IPC 的本质,是在隔离基础上建立受控通信协议。
process A address space process B address space
pointer 0x1234 pointer 0x1234
means A memory means B memory
communication must go through:
pipe/socketpair/shared memory/file/signal/kernel object2. IPC 工具选择地图
| 机制 | 适合 | 不适合 |
|---|---|---|
| pipe | 父子进程单向字节流 | 多对多复杂拓扑 |
| socketpair | 本机双向字节流 | 跨机器通信 |
| Unix domain socket | 本机多客户端服务、传 fd | Windows 原生兼容 |
| shared memory | 大块数据低拷贝共享 | 没有同步协议的随意读写 |
| signal | 简短通知、中断等待 | 携带复杂数据 |
| file/lock | 简单持久交换 | 高频低延迟通信 |
3. pipe 和 socketpair
pipe 是单向字节流;socketpair 是双向本机 socket。它们都没有消息边界,仍然要定义分帧。
parent
write command bytes
| pipe
v
child
read command bytes
parse frames管道容量有限。写端太快、读端太慢会阻塞或 EAGAIN;这也是背压的一种。
4. 共享内存不是自动同步
shared memory 只解决“两个进程能看到同一块内存”。它不解决并发访问、可见性、对象生命周期、崩溃恢复和版本兼容。跨进程共享 C++ 对象尤其危险,因为指针、虚表、allocator、mutex 状态都可能不适合跨进程。
shared memory region
header: magic/version/size/state
data : POD or explicit binary layout
sync : process-shared mutex/semaphore/futex/protocol5. 调度和阻塞
调度器决定哪个线程获得 CPU;系统调用、锁、page fault、I/O 都可能让线程让出 CPU。你看到的“程序慢”可能不是算法慢,而是在等待内核事件。
running
-> blocked on read
-> runnable but waiting for CPU
-> sleeping on mutex/futex
-> page fault handling6. 虚拟内存
每个进程看到自己的虚拟地址空间。虚拟地址通过页表映射到物理页或文件页。page fault 不一定是错误,它也可能是按需加载页面;但非法访问会变成 SIGSEGV。
virtual address
-> page table
-> physical page / file-backed page / not present
-> page fault if not present or permission mismatch7. copy-on-write
fork 后父子进程看起来都有同样内存,但实际常共享物理页并标记只读。某一方写入时内核复制页面。大进程 fork 后立刻 exec 通常成本可控;fork 后在多线程复杂进程里继续执行大量 C++ 逻辑则风险很高。
8. 进程间协议
IPC 仍然需要协议。pipe/socketpair 上传结构体内存不是稳定协议;要定义字节序、长度、版本、错误码、超时和关闭规则。
9. fd passing
Unix domain socket 可以传递 fd。传递的不是整数值本身,而是让接收进程获得指向同一内核资源的新 fd。这常用于 supervisor 把监听 socket 交给 worker。
10. 常见错误
- 把进程 A 的指针发给进程 B。
- shared memory 中放 std::string、虚函数对象或普通 mutex。
- pipe 协议没有长度和关闭约定。
- 父子进程忘记关闭不用 fd,导致 EOF 不出现。
- 把 CPU 不足、I/O 阻塞和锁等待混成一个“卡”。
- fork 后多线程子进程调用不安全逻辑。
11. 调试命令
strace -f -e read,write,pipe,sendmsg,recvmsg,futex,mmap ./program
ipcs -m
pmap -x <pid>
perf sched record ./program
perf sched latency
cat /proc/<pid>/maps12. 练习
- 用 pipe 实现父进程发长度前缀命令,子进程返回结果。
- 用 socketpair 实现双向 ping/pong。
- 用 mmap MAP_SHARED 共享一个计数器,再加进程间同步。
- fork 大数组后观察 copy-on-write 的内存变化。
- 用 strace 区分程序是在 read、futex 还是 page fault 附近等待。
13. 总结
IPC 的核心不是选哪个 API,而是先承认进程隔离,再设计通信边界。pipe/socketpair 是字节流,共享内存需要布局和同步,调度和虚拟内存决定等待与性能现场。
深化切片 1:最小实验
围绕 IPC 和 pipe 做一次工程练习。用一个最小程序观察一个系统行为,不要把 shell、库封装和业务代码混在一起。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 2:错误注入
围绕 pipe 和 socketpair 做一次工程练习。故意制造一个失败条件,例如文件不存在、权限不足、子进程退出码非零、管道对端关闭或映射越界。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 3:外部观察
围绕 socketpair 和 shared memory 做一次工程练习。用 ps、strace、lsof、pmap、ss、tcpdump 或调试器观察内核状态,而不是只看 C++ 变量。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 4:RAII 封装
围绕 shared memory 和 scheduler 做一次工程练习。把资源获取、移动、释放和失效状态写进类型,避免正常路径能释放、异常路径泄漏。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 5:并发边界
围绕 scheduler 和 virtual memory 做一次工程练习。系统调用可能阻塞,信号可能打断等待,多个线程可能同时操作同一个资源。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 6:生产复盘
围绕 virtual memory 和 page fault 做一次工程练习。记录命令、errno、pid、fd、路径、peer、字节数和状态,保证另一个人能复现。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 7:最小实验
围绕 page fault 和 copy-on-write 做一次工程练习。用一个最小程序观察一个系统行为,不要把 shell、库封装和业务代码混在一起。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 8:错误注入
围绕 copy-on-write 和 IPC 做一次工程练习。故意制造一个失败条件,例如文件不存在、权限不足、子进程退出码非零、管道对端关闭或映射越界。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 9:外部观察
围绕 IPC 和 pipe 做一次工程练习。用 ps、strace、lsof、pmap、ss、tcpdump 或调试器观察内核状态,而不是只看 C++ 变量。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 10:RAII 封装
围绕 pipe 和 socketpair 做一次工程练习。把资源获取、移动、释放和失效状态写进类型,避免正常路径能释放、异常路径泄漏。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 11:并发边界
围绕 socketpair 和 shared memory 做一次工程练习。系统调用可能阻塞,信号可能打断等待,多个线程可能同时操作同一个资源。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 12:生产复盘
围绕 shared memory 和 scheduler 做一次工程练习。记录命令、errno、pid、fd、路径、peer、字节数和状态,保证另一个人能复现。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 13:最小实验
围绕 scheduler 和 virtual memory 做一次工程练习。用一个最小程序观察一个系统行为,不要把 shell、库封装和业务代码混在一起。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 14:错误注入
围绕 virtual memory 和 page fault 做一次工程练习。故意制造一个失败条件,例如文件不存在、权限不足、子进程退出码非零、管道对端关闭或映射越界。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 15:外部观察
围绕 page fault 和 copy-on-write 做一次工程练习。用 ps、strace、lsof、pmap、ss、tcpdump 或调试器观察内核状态,而不是只看 C++ 变量。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 16:RAII 封装
围绕 copy-on-write 和 IPC 做一次工程练习。把资源获取、移动、释放和失效状态写进类型,避免正常路径能释放、异常路径泄漏。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 17:并发边界
围绕 IPC 和 pipe 做一次工程练习。系统调用可能阻塞,信号可能打断等待,多个线程可能同时操作同一个资源。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 18:生产复盘
围绕 pipe 和 socketpair 做一次工程练习。记录命令、errno、pid、fd、路径、peer、字节数和状态,保证另一个人能复现。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 19:最小实验
围绕 socketpair 和 shared memory 做一次工程练习。用一个最小程序观察一个系统行为,不要把 shell、库封装和业务代码混在一起。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 20:错误注入
围绕 shared memory 和 scheduler 做一次工程练习。故意制造一个失败条件,例如文件不存在、权限不足、子进程退出码非零、管道对端关闭或映射越界。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 21:外部观察
围绕 scheduler 和 virtual memory 做一次工程练习。用 ps、strace、lsof、pmap、ss、tcpdump 或调试器观察内核状态,而不是只看 C++ 变量。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 22:RAII 封装
围绕 virtual memory 和 page fault 做一次工程练习。把资源获取、移动、释放和失效状态写进类型,避免正常路径能释放、异常路径泄漏。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 23:并发边界
围绕 page fault 和 copy-on-write 做一次工程练习。系统调用可能阻塞,信号可能打断等待,多个线程可能同时操作同一个资源。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 24:生产复盘
围绕 copy-on-write 和 IPC 做一次工程练习。记录命令、errno、pid、fd、路径、peer、字节数和状态,保证另一个人能复现。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 25:最小实验
围绕 IPC 和 pipe 做一次工程练习。用一个最小程序观察一个系统行为,不要把 shell、库封装和业务代码混在一起。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 26:错误注入
围绕 pipe 和 socketpair 做一次工程练习。故意制造一个失败条件,例如文件不存在、权限不足、子进程退出码非零、管道对端关闭或映射越界。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 27:外部观察
围绕 socketpair 和 shared memory 做一次工程练习。用 ps、strace、lsof、pmap、ss、tcpdump 或调试器观察内核状态,而不是只看 C++ 变量。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 28:RAII 封装
围绕 shared memory 和 scheduler 做一次工程练习。把资源获取、移动、释放和失效状态写进类型,避免正常路径能释放、异常路径泄漏。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 29:并发边界
围绕 scheduler 和 virtual memory 做一次工程练习。系统调用可能阻塞,信号可能打断等待,多个线程可能同时操作同一个资源。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 30:生产复盘
围绕 virtual memory 和 page fault 做一次工程练习。记录命令、errno、pid、fd、路径、peer、字节数和状态,保证另一个人能复现。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 31:最小实验
围绕 page fault 和 copy-on-write 做一次工程练习。用一个最小程序观察一个系统行为,不要把 shell、库封装和业务代码混在一起。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 32:错误注入
围绕 copy-on-write 和 IPC 做一次工程练习。故意制造一个失败条件,例如文件不存在、权限不足、子进程退出码非零、管道对端关闭或映射越界。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 33:外部观察
围绕 IPC 和 pipe 做一次工程练习。用 ps、strace、lsof、pmap、ss、tcpdump 或调试器观察内核状态,而不是只看 C++ 变量。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 34:RAII 封装
围绕 pipe 和 socketpair 做一次工程练习。把资源获取、移动、释放和失效状态写进类型,避免正常路径能释放、异常路径泄漏。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 35:并发边界
围绕 socketpair 和 shared memory 做一次工程练习。系统调用可能阻塞,信号可能打断等待,多个线程可能同时操作同一个资源。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。
深化切片 36:生产复盘
围绕 shared memory 和 scheduler 做一次工程练习。记录命令、errno、pid、fd、路径、peer、字节数和状态,保证另一个人能复现。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,IPC、调度与虚拟内存边界 就越不容易学成 API 背诵。