C++后端工程师面试宝典 - 第4节

4. 操作系统与网络基础:进程与线程、同步机制、TCP三次握手、IO多路复用

本章定位:C++后端面试必考操作系统与网络基础,重点在进程线程区别、同步原语、TCP连接建立、IO多路复用模型。掌握回答框架可覆盖90%高频问题。
OS与网络面试核心 进程与线程 定义与区别 · 切换开销 · 通信方式 同步机制 互斥锁·条件变量·信号量 TCP三次握手 状态变化·SYN Flood·Time_Wait IO多路复用 select·poll·epoll 回答框架:定义→对比/流程→场景→避坑
复习提示:将上图五个分支作为骨架,针对每个面试问题先定位到对应分支,再套用底部回答框架展开。

📌 面试问答1:进程与线程的区别

面试问题请解释进程与线程的区别,并举例说明在多线程编程中如何选择。
考察点是否理解OS级调度基本概念、上下文切换代价、资源共享方式。
回答框架① 定义:进程是资源分配最小单位,线程是CPU调度最小单位。
② 区别:进程有独立地址空间,线程共享进程资源;进程切换开销大(页表、TLB),线程切换轻量;进程间通信需IPC,线程间直接读写共享内存。
③ 场景:计算密集型+多核用线程池;需要强隔离用多进程。
示例回答进程拥有独立的虚拟地址空间和系统资源,线程是进程内的执行流,共享代码段和数据段。线程切换只需保存寄存器状态,而进程切换需要切换页表,开销高。例如在Web服务器中,用线程处理请求可降低延迟,但若要运行不可信插件,用进程隔离更安全。
可能追问① 什么是协程?与线程的差异?② Linux下如何创建一个新进程?fork()的写时复制原理?③ 多线程中如何保证数据一致性?
避坑提醒❌ 不要混淆“线程比进程快”为结论;实际在简单计算任务中线程优势明显,但在需要大量fork的场景下进程也有性能优势。明确说“线程切换快”但也要提共享资源同步成本。
TCP三次握手追问路径 为什么必须是三次?两次不行吗? 核心:防止失效连接请求 回答:避免僵尸连接 追问:SYN Flood 怎么应对? 追问:Time_Wait过多如何优化? 回答:SYN Cookie / 减小超时 回答:SO_REUSEADDR / 调整参数

📌 面试问答2:解释TCP三次握手过程

面试问题描述TCP三次握手的过程,并说明为什么需要第三次握手。
考察点对TCP状态转移的理解、协议设计的可靠性思考、对失效连接的控制。
回答框架① 流程:客户端发送SYN(seq=x)→服务端回复SYN+ACK(seq=y, ack=x+1)→客户端发送ACK(ack=y+1)。
② 原因:第三次握手防止已失效的SYN请求连接建立,保证双方都确认对方接收能力正常。
③ 状态:客户端SYN_SENT→ESTABLISHED;服务端LISTEN→SYN_RCVD→ESTABLISHED。
示例回答三次握手确保双方协商初始序列号并确认收发能力。如果只有两次,服务端无法区分客户端是否收到了自己发送的SYN+ACK,可能导致服务端持续等待。第三次ACK是客户端对服务端序列号的确认,这样连接才可靠。
可能追问① 什么是半连接队列和全连接队列?② 如果客户端发送SYN后宕机,服务端会一直等待吗?③ 四次挥手为什么是四次?
避坑提醒❌ 不要只背流程;必须说清楚“确认双方收发能力”及“防止历史连接”。面试官常会深入问SYN Flood和backlog配置,提前准备。

📌 面试问答3:IO多路复用select/poll/epoll对比

面试问题select、poll、epoll的区别是什么?epoll为什么性能更好?
考察点对IO模型的理解、系统调用的性能差异、大规模并发时的瓶颈分析。
回答框架① 数据结构:select使用固定长度fd_set(1024限制);poll使用pollfd数组,无上限;epoll使用红黑树+双向链表。
② 触发方式:select/poll水平触发;epoll支持边缘触发(ET)和水平触发(LT)。
③ 效率:select/poll每次需拷贝全部fd到内核并线性遍历;epoll通过回调只返回就绪fd,O(1)复杂度。
示例回答select有描述符上限(默认1024),每次调用需将fd集合从用户态拷贝到内核态,遍历所有fd;epoll使用事件驱动机制,内核通过回调将就绪fd放入链表,用户通过epoll_wait直接获取,无上限且避免无关遍历。因此epoll在处理大量并发连接时性能远优于select。
可能追问① epoll的LT和ET模式有什么区别?何时用ET?② 如何解决epoll惊群问题?③ Reactor模式如何用epoll实现?
避坑提醒❌ 不要简单说“epoll比select快”,需要具体分析场景(少量连接下select可能更快因为epoll需要维护回调结构)。注意边缘触发(ET)必须配合非阻塞IO使用,否则会导致死锁。

同步机制核心对比

同步原语作用域特点典型场景注意
互斥锁(mutex)线程间独占访问,可重入或非可重入保护临界区数据避免持有锁时调用可能引起阻塞的函数
条件变量(cond)线程间配合mutex,等待/通知机制生产者-消费者必须与unique_lock配对使用
信号量(sem)线程/进程计数型,控制并发访问数量限制资源池大小注意PV操作的原子性
读写锁(rwlock)线程间读共享、写独占写少读多场景避免写者饥饿
原子操作(atomic)线程间无锁,CAS原理计数器、状态标志不支持复杂数据结构

项目案例:高性能IM服务器

项目名称基于epoll的即时通讯(IM)后端服务器
业务背景为公司内部团队提供实时消息服务,支持文本、图片和文件传输,要求低延迟、高吞吐。
规模指标同时在线用户约5万,日均消息量2000万条,P99延迟<10ms。
技术栈C++17 · epoll(ET模式) · 线程池 · protobuf · MySQL · Redis(缓存用户状态)
核心难点① 海量连接下epoll惊群优化(使用EPOLLEXCLUSIVE)
② 粘包问题:自定义消息头(4字节长度+1字节类型)
③ 线程池与epoll事件循环的协调(Reactor模式)
面试高频追问① epoll唤醒线程时如何避免惊群?→ 设置EPOLLEXCLUSIVE或用SO_REUSEPORT。
② 如何处理消息乱序?→ 服务端通过序列号排序,客户端使用滑动窗口。
③ 为什么选择protobuf而非json?→ 二进制序列化快,解析性能高。
④ 数据库压力如何缓解?→ 写操作先入Redis队列,异步批量落库。
可迁移回答话术“我在IM项目中负责网络层开发,使用epoll ET+非阻塞IO实现高性能事件驱动。通过区分业务类型设计线程池模型,避免锁竞争。针对粘包问题设计了TLV消息格式,保证协议健壮性。这个架构也可用于其他高并发网关或游戏服务器。”
避坑总提醒:操作系统与网络基础是面试翻车重灾区,务必手画三次握手状态图、写出epoll_ctl/epoll_wait的调用序列。面试时主动延展到项目落地场景(如在哪用过条件变量、如何用epoll优化吞吐),让考官看到你的工程深度。