Channel 通道
CHAPTER 03

Channel 通道

3 分钟阅读 · 617 字

对应文件:

  • 接口: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 支持超时等待
全部章节