|
@@ -0,0 +1,180 @@
|
|
|
|
|
+# 第四批 OS / 网络 / C++ 八股 · 复习总结(6 主题)
|
|
|
|
|
+
|
|
|
|
|
+> 使用说明:先自测「判别规则速查表」,遮住右列自答;再做「综合练习题」,最后对答案。
|
|
|
|
|
+> 面试前只翻本目录,不背题。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 一、判别规则速查表(遮右自测)
|
|
|
|
|
+
|
|
|
|
|
+| # | 主题 | 一句话判别规则 |
|
|
|
|
|
+| -- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
+| 41 | 进程 vs 线程 | 要**崩溃隔离/资源独立 → 进程**(切换重:换地址空间);要**轻快/共享数据 → 线程**(切换轻、一个崩全崩);线程共享变量必须同步 |
|
|
|
|
|
+| 42 | 僵尸/孤儿/守护进程 | 子死+父未 wait=**僵尸**;父先死+子活=**孤儿**(init 收养);主动 **setsid 脱离终端=守护**;ctrl+Z+bg 不算(还连终端会收 SIGHUP) |
|
|
|
|
|
+| 43 | TCP 如何保证可靠 | **ACK 确认 + 重传(超时/快重传)+ 序号(判重复/乱序)+ 校验(查损坏)+ 滑动窗口(接收方)+ 拥塞控制(网络)**;可靠是"尽力而为"非绝对 |
|
|
|
|
|
+| 44 | C++ struct vs class | **功能完全相同**;唯一区别=**默认访问权限**(struct public / class private)+ **默认继承**(struct public 继承 / class private 继承) |
|
|
|
|
|
+| 45 | C++ 构造/析构(RAII)| 构造=创建时初始化、析构=销毁时清理;**RAII=栈对象自动析构**(非 new/delete);移动给临时对象、拷贝给存活对象;**容器默认走移动,移动不可用才拷贝** |
|
|
|
|
|
+| 46 | SMP/多核 | 多核=**真并行**(单核=并发);**共享数据必须原子/锁**;**缓存一致性(MESI)+ 伪共享(同缓存行)**是坑;**关中断只关本核**,多核要自旋锁 |
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 二、易混对比集中营(高频考点串讲)
|
|
|
|
|
+
|
|
|
|
|
+### 进程 vs 线程
|
|
|
|
|
+
|
|
|
|
|
+| | 进程 | 线程 |
|
|
|
|
|
+| ------ | ------------ | -------------------- |
|
|
|
|
|
+| 地址空间 | 独立(隔墙) | 共享(同一进程) |
|
|
|
|
|
+| 切换开销 | 重(换页表/TLB) | 轻(换寄存器/栈指针)|
|
|
|
|
|
+| 崩溃影响 | 崩一个不影响其他 | 一个崩 → 整个进程崩 |
|
|
|
|
|
+| 通信 | IPC(管道/消息/共享内存) | 共享变量 + 锁 |
|
|
|
|
|
+
|
|
|
|
|
+### 僵尸 / 孤儿 / 守护
|
|
|
|
|
+
|
|
|
|
|
+| | 僵尸 | 孤儿 | 守护 |
|
|
|
|
|
+| ------ | ------------ | ------------------ | ---------------- |
|
|
|
|
|
+| 谁死了 | 子死,父活 | 父死,子活 | 谁都没死 |
|
|
|
|
|
+| 本质 | 残留 PCB 未回收 | init 收养继续跑 | 主动脱离终端后台 |
|
|
|
|
|
+| 处理 | 父 wait 回收 | init 等完再回收 | 自己独立 |
|
|
|
|
|
+
|
|
|
|
|
+**僵尸三解法**:父 wait() / 双 fork(孙被 init 收)/ signal(SIGCHLD, SIG_IGN)。
|
|
|
|
|
+**守护创建**:fork → setsid → 再 fork(防重新获取终端)→ chdir("/") → umask(0) → close(0/1/2)。
|
|
|
|
|
+
|
|
|
|
|
+### TCP vs UDP
|
|
|
|
|
+
|
|
|
|
|
+| | TCP | UDP |
|
|
|
|
|
+| ------ | ---------------------------- | ----------------------- |
|
|
|
|
|
+| 可靠 | 可靠(序号/确认/重传) | 不可靠(发了不管) |
|
|
|
|
|
+| 连接 | 面向连接(三次握手) | 无连接 |
|
|
|
|
|
+| 速度 | 慢(要确认) | 快(不确认) |
|
|
|
|
|
+| 场景 | 文件/网页/邮件 | 视频直播/DNS/游戏 |
|
|
|
|
|
+
|
|
|
|
|
+### 滑动窗口 vs 拥塞控制(两个窗口取最小值)
|
|
|
|
|
+
|
|
|
|
|
+| | 滑动窗口 | 拥塞控制 |
|
|
|
|
|
+| ------ | ------------------ | -------------------- |
|
|
|
|
|
+| 能力 | 接收方能力 | 网络能力 |
|
|
|
|
|
+| 防 | 淹没接收方 | 搞崩网络 |
|
|
|
|
|
+| 手段 | 接收方报 Window | 慢启动/拥塞避免/快恢复 |
|
|
|
|
|
+
|
|
|
|
|
+### 序号 vs 校验和
|
|
|
|
|
+
|
|
|
|
|
+| | 序号(Seq) | 校验和(Checksum) |
|
|
|
|
|
+| ------ | ---------------- | ------------------------ |
|
|
|
|
|
+| 作用 | 判**重复/乱序** | 查**数据完整性**(坏了没)|
|
|
|
|
|
+| 响应 | 丢弃重复/重排 | 丢弃损坏 |
|
|
|
|
|
+
|
|
|
|
|
+### 三次握手 vs 四次挥手
|
|
|
|
|
+
|
|
|
|
|
+| | 三次握手 | 四次挥手 |
|
|
|
|
|
+| ------ | ---------------- | ------------------------ |
|
|
|
|
|
+| 目的 | 建立连接 | 断开连接 |
|
|
|
|
|
+| 次数 | 3(SYN+ACK 合并)| 4(FIN/ACK 分开,半关闭)|
|
|
|
|
|
+| 为什么 | 防旧 SYN 浪费资源 | 全双工,一方 FIN 还能收 |
|
|
|
|
|
+
|
|
|
|
|
+### struct vs class vs union
|
|
|
|
|
+
|
|
|
|
|
+| | struct | class | union |
|
|
|
|
|
+| ---------- | ----------------- | ------------------ | --------------------- |
|
|
|
|
|
+| 默认访问 | public | private | public |
|
|
|
|
|
+| 内存 | 累加 | 累加 | 共用一块(取最大) |
|
|
|
|
|
+| 用途 | 聚合数据 | 封装/多态 | 协议解析/类型转换 |
|
|
|
|
|
+| 构造/析构 | 有 | 有 | 有(C++11 起) |
|
|
|
|
|
+
|
|
|
|
|
+### 深拷贝 vs 浅拷贝 vs 移动
|
|
|
|
|
+
|
|
|
|
|
+| | 浅拷贝 | 深拷贝 | 移动 |
|
|
|
|
|
+| ------ | ---------------- | ------------------ | -------------------- |
|
|
|
|
|
+| 指针 | 复制指针值(共享)| 新分配+复制数据 | 偷指针+原对象置空 |
|
|
|
|
|
+| 后果 | 双重释放崩溃 | 安全 | 安全且 O(1) |
|
|
|
|
|
+| 给谁 | 禁用 | 存活的已存在对象 | 用完即弃的临时对象 |
|
|
|
|
|
+
|
|
|
|
|
+**移动构造三要素**:右值引用参数 + 转移资源 + 原对象置空(防双重释放)。
|
|
|
|
|
+
|
|
|
|
|
+### 移动优先原则(核心)
|
|
|
|
|
+
|
|
|
|
|
+- 标准库容器重定位元素:**默认走移动**,移动不可用(`=delete`/未定义/**非 noexcept**)才走拷贝
|
|
|
|
|
+- **为什么 noexcept 关键**:vector 扩容要强异常安全,移动可能抛异常就回退拷贝
|
|
|
|
|
+- 推论:`std::unique_ptr`(只移动不拷贝)能存 vector
|
|
|
|
|
+- C++17 保证复制省略:`return T();` 直接构造,拷贝 `=delete` 也能编译(C++11/14 不行)
|
|
|
|
|
+
|
|
|
|
|
+### 并行 vs 并发 / SMP vs AMP
|
|
|
|
|
+
|
|
|
|
|
+| | 并行 | 并发 |
|
|
|
|
|
+| ------ | ------------------ | -------------------- |
|
|
|
|
|
+| 定义 | 同一时刻同时执行 | 轮流切换,同一刻一个 |
|
|
|
|
|
+| 需要 | 多核 | 单核即可 |
|
|
|
|
|
+
|
|
|
|
|
+| | SMP | AMP |
|
|
|
|
|
+| ------ | ------------------ | --------------------- |
|
|
|
|
|
+| 核关系 | 对等(对称) | 不等(异构分工) |
|
|
|
|
|
+| 例子 | 普通多核 CPU | big.LITTLE、GPU+CPU |
|
|
|
|
|
+
|
|
|
|
|
+### 原子操作 vs 锁 vs 自旋锁
|
|
|
|
|
+
|
|
|
|
|
+| | 原子操作 | 锁 | 自旋锁 |
|
|
|
|
|
+| ------ | -------------- | ------------ | -------------- |
|
|
|
|
|
+| 实现 | 硬件原子指令 | 原子指令+睡眠| 忙等轮询 |
|
|
|
|
|
+| 开销 | 最小 | 有切换 | 忙等耗 CPU |
|
|
|
|
|
+| 适用 | 单变量(count++)| 多步临界区 | 多核短临界区 |
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 三、综合练习题(答完再对答案)
|
|
|
|
|
+
|
|
|
|
|
+### 判断题(对/错 + 一句话理由)
|
|
|
|
|
+
|
|
|
|
|
+1. 浏览器一个标签页崩了,其他标签页不受影响,是因为每个标签页用了独立线程。答:
|
|
|
|
|
+2. 孤儿进程会被 init 进程"回收清除",就像僵尸被父进程 wait 那样。答:
|
|
|
|
|
+3. 一个程序用 daemon() 脱离终端后台运行,但父进程还活着——它不是守护进程,因为守护必须父进程先死。答:
|
|
|
|
|
+4. 终端里 Ctrl+Z 挂起再 bg 放到后台的进程,就是守护进程。答:
|
|
|
|
|
+5. TCP 有拥塞控制,所以 TCP 传输一定是可靠的。答:
|
|
|
|
|
+6. UDP 没有序号和确认,所以 UDP 数据包一定会丢。答:
|
|
|
|
|
+7. TCP 接收方靠校验和判断收到的包是不是重复的。答:
|
|
|
|
|
+8. C++ 里 struct 只能放数据,class 只能放方法,两者不能混用。答:
|
|
|
|
|
+9. `class A { int x; };` 外面写 `A a; a.x = 5;` 报错,改成 `struct A` 就能编译。答:
|
|
|
|
|
+10. `struct` 和 `class` 同样的成员,sizeof 结果不同。答:
|
|
|
|
|
+11. 把 `new`/`delete` 换成 RAII 后,中途 return 时资源就一定能被释放。答:
|
|
|
|
|
+12. 移动构造是复制一份数据给新对象,所以比拷贝构造慢。答:
|
|
|
|
|
+13. 一个类声明了析构函数,编译器仍然会隐式生成移动构造函数。答:
|
|
|
|
|
+14. 多核系统里,关中断(临界区)可以保护共享数据不被其他核访问。答:
|
|
|
|
|
+15. `arr[0]` 和 `arr[100]` 两个变量由不同线程各写一个,因为离得远,绝不会伪共享。答:
|
|
|
|
|
+16. 单核 CPU 上跑两个线程,它们同一时刻可以并行执行。答:
|
|
|
|
|
+
|
|
|
|
|
+### 填空题
|
|
|
|
|
+
|
|
|
|
|
+17. 僵尸进程产生的原因:子进程已退出、父进程没有调用 ____ 回收。
|
|
|
|
|
+18. 孤儿进程最终由 ____(PID 1)收养,等它运行完再回收。
|
|
|
|
|
+19. 守护进程创建的关键一步是调用 ____ 创建新会话、脱离控制终端。
|
|
|
|
|
+20. TCP 用 ____ 号判断重复/乱序,用 ____ 检查数据完整性。
|
|
|
|
|
+21. TCP 靠 ____(接收方能力)和 ____(网络能力)两个窗口控制发送速度,实际取 ____ 值。
|
|
|
|
|
+22. TCP 四次挥手比三次握手多一次,是因为 FIN 和 ____ 要分开发送(半关闭状态)。
|
|
|
|
|
+23. C++ struct 默认访问权限是 ____,class 默认是 ____。
|
|
|
|
|
+24. C++ struct 默认 ____ 继承,class 默认 ____ 继承。
|
|
|
|
|
+25. 移动构造的签名是 `ClassName(____)`,参数是右值引用。
|
|
|
|
|
+26. 移动构造三要素:右值引用参数、____、____(防双重释放)。
|
|
|
|
|
+27. 标准库容器重定位元素时默认走 ____,移动不可用时才走 ____。
|
|
|
|
|
+28. 移动构造声明为 ____ 后,vector 扩容才放心用移动(保证强异常安全)。
|
|
|
|
|
+29. C++17 的 ____(特性)让 `return T();` 直接构造,无需拷贝/移动构造。
|
|
|
|
|
+30. 多核保护临界区要用 ____ 锁(忙等),不能只靠关中断。
|
|
|
|
|
+31. 伪共享的判断标准:变量地址间隔 ____(小于/大于)缓存行大小(通常 64 字节)。
|
|
|
|
|
+
|
|
|
|
|
+### 场景 / 代码判断
|
|
|
|
|
+
|
|
|
|
|
+32. 场景:多个并发任务都要频繁访问同一份数据,且要求切换轻快 → 用进程还是线程?为什么线程崩会拖垮整个进程?
|
|
|
|
|
+33. 场景:父进程不关心子进程退出状态,想彻底不产生僵尸 → 给出两种方案。
|
|
|
|
|
+34. 场景:视频直播丢几帧没关系,但不能卡顿 → 用 TCP 还是 UDP?为什么不用另一个?
|
|
|
|
|
+35. 代码判断:`std::unique_ptr<int> u(new int(5));` 能不能放进 `std::vector<std::unique_ptr<int>>`?扩容时怎么搬?
|
|
|
|
|
+36. 场景:4 核 CPU 上两个线程分别绑核 0、核 1,同时执行 `count++`(共享变量)不加锁 → 结果一定对吗?为什么?
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 四、答案(已分离)
|
|
|
|
|
+
|
|
|
|
|
+答案解析已单独存放,避免自测时不小心看到答案:
|
|
|
|
|
+
|
|
|
|
|
+> **`第四批复习总结-答案.md`**(同目录)——完成全部 36 题后再翻开对照。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+_复习目标:每条规则能自己讲出"为什么",不只记住结论。_
|