这 8 道题同样不是孤立的,它们构成了一个从“单机并发基础”到“网络服务工程架构”的递进链条。核心主线是:先分清进程与线程 → 再理解它们分别如何通信 → 再把这些通信机制放到网络环境里 → 最后落地到 LLM 推理服务的高并发架构。
下面先串成知识网络,再做一张交互图。
一、8 道题的归类与联系
| 主题层 | 对应题号 | 核心问题 |
|---|---|---|
| 基础概念 | 6 | 进程和线程的区别是什么 |
| 通信机制 | 1、3、4 | 进程怎么通信、Socket 是什么、TCP/UDP 怎么选 |
| 并发服务器模型 | 2 | 多进程与多线程服务器各自的优劣 |
| 同步与安全 | 7、8 | 共享内存安全吗、怎么用同步原语实现推理队列 |
| 工程架构 | 5 | 高性能网络服务如何支撑 LLM 推理和流式输出 |
二、逐层拆解联系
1. 进程 vs 线程:一切并发问题的起点
第 6 题是这张地图的地基。
| 维度 | 进程(Process) | 线程(Thread) |
|---|---|---|
| 资源拥有 | 独立地址空间、页表、文件描述符表 | 共享所属进程的地址空间和资源 |
| 切换开销 | 大(需切换页表、刷新 TLB) | 小(只需保存/恢复寄存器和栈) |
| 通信方式 | 必须借助 IPC | 直接读写共享内存,但需要同步 |
| 隔离性 | 强,一个进程崩溃不影响其他进程 | 弱,一个线程崩溃可能拖垮整个进程 |
| 创建开销 | 大(fork + 写时复制) | 小 |
联系:
- 正是因为进程有独立地址空间,所以进程间通信才需要 IPC 机制(第 1 题)。
- 正是因为线程共享地址空间,所以线程通信简单但必须有同步原语(第 7、8 题)。
- 并发服务器选型时,多进程模型利用的是“隔离性”,多线程模型利用的是“共享与低开销”(第 2 题)。
2. 通信机制:IPC、Socket、TCP/UDP
第 1、3、4 题讲的是同一件事的不同尺度。
(1)进程间通信 IPC(第 1 题)
Linux/Unix 经典 IPC 包括:
| 机制 | 特点 | 适用场景 |
|---|---|---|
管道 pipe | 半双工,父子进程间 | shell 管道、简单父子通信 |
| 命名管道 FIFO | 无亲缘关系进程间 | 本地固定节点通信 |
| 消息队列 | 消息为单位,内核维护 | 异步解耦,消息边界清晰 |
| 共享内存 | 速度最快,需配合信号量/mutex | 大数据量、高频本地通信 |
| 信号量 | 用于同步,不直接传数据 | 临界区保护 |
| 信号 | 异步通知 | 事件通知、中断式处理 |
| Socket | 最通用,可本地可跨网络 | 分布式、网络服务 |
(2)Socket 与其他通信方式的区别(第 3 题)
- Socket 是统一抽象,同一套 API(
socket/bind/listen/accept/connect/send/recv)既可以用于本机进程通信(Unix Domain Socket),也可以用于跨网络通信(Network Socket)。 - 其他 IPC 方式大多只能本机使用。
- Socket 编程天然与网络协议栈结合,是构建网络服务的入口。
(3)TCP 与 UDP(第 4 题)
| 特性 | TCP | UDP |
|---|---|---|
| 连接 | 面向连接 | 无连接 |
| 可靠性 | 可靠传输,保证顺序 | 不保证可靠、不保证顺序 |
| 重传机制 | 超时重传、快速重传、SACK | 无 |
| 拥塞控制 | 有 | 无 |
| 头部开销 | 大 | 小 |
| 适用场景 | HTTP、流式输出、文件传输 | DNS、视频流、实时游戏 |
TCP 什么时候会重传?
- 超时重传:发送端启动 RTO 定时器,ACK 没按时到达就重传。
- 快速重传:收到 3 个重复 ACK,认为包丢失,不等 RTO 直接重传。
- SACK:接收端告知具体丢失的段,只重传丢失部分。
联系:Socket 是 API,TCP/UDP 是 Socket 可以选择的传输协议。LLM 流式输出通常基于 TCP 长连接(HTTP/1.1 chunked、SSE、WebSocket),因为要保证顺序和可靠。
3. 并发服务器模型:多进程 vs 多线程
第 2 题是把前面概念用于网络服务设计。
| 模型 | 代表 | 优点 | 缺点 |
|---|---|---|---|
| 多进程 | fork() 一个连接一个子进程 | 隔离性强,崩溃不相互影响 | 创建和切换开销大,进程数受限 |
| 多线程 | 一个连接一个线程 | 共享地址空间,切换较快 | 一个线程崩溃可能影响整体,同步复杂 |
| IO 多路复用 | select/poll/epoll + 少量线程 | 单线程/少量线程处理大量连接,资源省 | 编程复杂,适合 IO 密集型 |
| 协程 + IO 多路复用 | epoll + coroutine(如 libco、libgo) | 用户态切换极轻,代码像同步 | 需要生态支持,调度机制要设计好 |
现代 C++ 高性能网络服务通常采用Reactor 模式:一个主线程用 epoll 监听连接,多个 Worker 线程处理读写和计算。这样兼顾并发能力和资源利用率。
联系:选择多进程还是多线程,取决于你要“隔离”还是“共享”;而现代高并发服务往往 neither——用 epoll + 线程池。
4. 同步与安全:共享内存和同步原语
第 7、8 题是线程并发编程的核心。
(1)共享内存安全吗?(第 7 题)
共享内存本身是不安全的。多个线程同时读写同一块内存,如果没有同步,会出现:
- 数据竞争(Data Race)
- 读脏数据
- 可见性问题(一个线程的修改对另一个线程不可见)
保护措施:
- 互斥锁
std::mutex:保护临界区,同一时刻只有一个线程进入。 - 条件变量
std::condition_variable:线程间等待/通知,用于生产者-消费者模型。 - 原子操作
std::atomic:无锁同步,适合计数器、标志位等简单共享状态。 - 内存屏障/顺序语义:
std::atomic的memory_order控制指令重排和可见性。 - 读写锁
shared_mutex:读多写少场景。 - 无锁数据结构:CAS 循环实现队列、栈等。
(2)线程、mutex、condition_variable、atomic 如何用于推理队列?(第 8 题)
典型 LLM 推理服务的请求队列实现:
std::queue<Request> q;
std::mutex mtx;
std::condition_variable cv;
std::atomic<bool> stop{false};
// 接入线程(生产者)
void enqueue(Request req) {
{
std::lock_guard<std::mutex> lock(mtx);
q.push(req);
}
cv.notify_one(); // 唤醒一个 Worker
}
// Worker 线程(消费者)
void worker() {
while (!stop) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return !q.empty() || stop; });
if (stop) break;
Request req = q.front();
q.pop();
lock.unlock();
run_inference(req); // 释放锁后再做耗时推理
}
}
| 原语 | 作用 |
|---|---|
std::mutex | 保护队列的入队/出队操作 |
std::condition_variable | 无请求时让 Worker 阻塞等待,避免空转 |
std::atomic<bool> | 停止标志,线程安全地通知所有线程退出 |
std::atomic<int> | 统计正在执行的请求数、请求 ID 等 |
联系:共享内存让线程通信变得高效,同步原语让这种共享变得安全。推理队列就是“共享内存 + 同步原语”最经典的工程模式之一。
5. 工程落地:C++ 高性能网络服务支撑 LLM 推理和流式输出
第 5 题是前面所有知识的综合应用。
一个 LLM 推理服务通常分三层:
关键技术点:
| 环节 | 技术选择 | 原因 |
|---|---|---|
| 网络接入 | epoll + 线程池 / io_uring | 高并发、低延迟 |
| 协议 | HTTP/1.1 chunked、SSE、WebSocket | 支持长连接和流式输出 |
| 传输层 | TCP | 保证 token 顺序和可靠性 |
| 推理调度 | 请求队列 + 优先级/批处理 | 提升吞吐,降低平均延迟 |
| 线程同步 | mutex + condition_variable + atomic | 安全高效地协调生产和消费 |
| 流式输出 | 队列缓存 + 异步推送 | 生成一个 token 推一个 token |
| 超时/取消 | condition_variable + atomic 标志 | 支持客户端断开和请求取消 |
联系:LLM 推理服务同时用到了网络通信(Socket/TCP/HTTP)、并发模型(epoll + 线程池)、同步原语(mutex/condition_variable/atomic)和进程/线程知识。
三、对 C/C++ 多线程、并发与网络通信的整体理解
建议你按这条主线建立认知:
- 进程是资源分配单位,线程是 CPU 调度单位。先把这个区分刻进脑子里。
- 进程间通信靠 IPC,线程间通信靠共享内存 + 同步。Socket 是唯一能跨网络的通信方式。
- TCP 提供可靠有序传输,适合 LLM 流式输出;UDP 适合容忍丢包、追求低延迟的场景。
- 现代高并发服务器不是“一个连接一个进程/线程”,而是用
epoll/io_uring+ 线程池。 - 并发编程的核心矛盾是“共享”与“安全”。mutex 保护临界区,condition_variable 协调时序,atomic 处理简单状态。
- 工程上要从“能跑”到“好跑”:考虑连接管理、超时、背压、优雅退出、资源隔离、性能监控。
四、记忆口诀
进程线程先分清,IPC 管进程间通信;
Socket 跨网又本地,TCP 可靠 UDP 轻;
并发服务器 epoll 赢,一个连接一线程已过时;
共享内存要同步,mutex 临界 cv 等;
atomic 计数量,推理队列最典型;
LLM 服务长连接,流式输出靠 TCP。
下面给你做一张交互图,把这 8 道题的关系和 LLM 推理服务架构可视化出来。
做好了!这是第二张交互图:C/C++ 并发与网络通信全景图。
用法:
- 顶部 4 个视图可切换:
- 关系总览:进程、线程、IPC、Socket、TCP/UDP、并发服务器、同步原语之间的关系。
- 并发服务器模型:对比多进程、多线程、
epoll + 线程池、协程。 - LLM 推理服务架构:从客户端 → 接入层 → 推理队列 → Worker → 引擎 → 流式输出的完整链路。
- 同步原语选择:共享内存、mutex、condition_variable、atomic 的决策关系。
- 点击图中任意节点,右侧会显示该节点的职责、特点、适用场景和代码示例。

9154

被折叠的 条评论
为什么被折叠?



