CHAPTER 03
Channel 通道
对应文件:
- 接口:
include/Channel.h - 实现:
src/Channel.cpp(当前仅包含头文件,核心逻辑在模板头文件)
1. 模块定位
Channel<T> 是一个 Go 风格通道抽象,支持:
- 无缓冲通道(
buf=0)的同步发送/接收 - 有缓冲通道(
buf>0)的队列式发送/接收 close()关闭语义- 操作符语法糖(
<</>>)
该模块用于线程间安全通信,采用互斥锁 + 条件变量实现阻塞等待。
2. 数据结构
核心成员:
buffer_size:通道容量,0表示无缓冲std::mutex mtx:保护内部状态std::condition_variable cv:发送和接收统一唤醒std::queue<T> queue:有缓冲模式的数据队列T value+bool has_value:无缓冲模式下的单值槽bool closed:关闭状态
3. 关键函数与行为
3.1 push(T val)
- 加锁后进入
cv.wait,等待“可写”条件:- 已关闭:立即结束等待
- 无缓冲:
!has_value - 有缓冲:
queue.size() < buffer_size
- 若
closed == true,抛出runtime_error("push to closed channel") - 写入数据:
- 无缓冲:写入
value,置has_value=true - 有缓冲:
queue.push
- 无缓冲:写入
cv.notify_one()唤醒等待线程
3.2 pop()
- 加锁后进入
cv.wait,等待“可读”条件:- 已关闭:结束等待(后续判断是否仍可取)
- 无缓冲:
has_value == true - 有缓冲:
queue非空
- 对“关闭且空”场景抛异常:
runtime_error("pop from closed and empty channel")
- 读取数据:
- 无缓冲:取
value,并has_value=false - 有缓冲:
front + pop
- 无缓冲:取
notify_one()后返回值
3.3 close()
- 幂等:重复调用直接返回
- 设置
closed=true后notify_all,唤醒所有阻塞发送者/接收者
3.4 operator<< / operator>>
<<:调用push>>:内部捕获pop异常并返回false,提供非异常风格读取
4. 并发语义(面试可讲)
- 线程安全:所有状态读写均在
mtx保护下 - 阻塞模型:
- 无缓冲通道具备“发送-接收握手”语义
- 有缓冲通道具备“容量背压”语义
- 关闭模型:
- 关闭后不能再写
- 关闭后仍允许读完剩余数据
- 读空后报错(或
>>返回false)
5. 适用场景
- 生产者-消费者任务投递
- 线程间状态事件通知
- pipeline 流程阶段串联
6. 风险与改进建议
- 当前
T value在无缓冲模式必须可默认构造(成员对象存在),对某些类型不友好- 可改为
std::optional<T> value
- 可改为
operator>>吃掉所有异常,错误细节丢失- 可增加
try_pop/pop_or_error分离接口
- 可增加
- 缺少超时 API
- 可补
push_for/pop_for支持超时等待
- 可补