一、基本概念
1. 等待队列(Wait Queue)
定义:等待队列是内核通用的进程阻塞/唤醒机制,用于让进程等待某个任意条件(如资源可用、信号到达、事件触发)。
核心结构:
struct wait_queue_head_t { spinlock_t lock; // 保护队列的自旋锁 struct list_head head; // 等待进程的链表头 }; struct wait_queue_entry { struct task_struct *task; // 等待的进程 struct list_head entry; // 链表节点 // 可选的回调函数(如poll) };关键操作:
初始化:
init_waitqueue_head(wait_queue_head_t *q)添加等待进程:
add_wait_queue(q, entry)(将进程加入队列)设置进程状态:
set_current_state(TASK_UNINTERRUPTIBLE/TASK_INTERRUPTIBLE)(标记为阻塞)调度:
schedule()(主动让出CPU)唤醒:
wake_up(q)(唤醒队列中所有符合条件的进程)、wake_up_interruptible(q)(仅唤醒可中断进程)
特点:灵活支持复杂条件判断(如循环检查变量状态),适用于生产者-消费者、多条件等待等场景。
2. 完成量(Completion)
定义:完成量是基于等待队列的简化封装,专门用于等待单一事件完成(如“操作已结束”“任务已完成”)。
核心结构:
struct completion { unsigned int done; // 事件完成计数(0表示未完成) wait_queue_head_t wait; // 底层等待队列(继承自wait queue) };关键操作:
初始化:
init_completion(struct completion *x)(done=0)或DECLARE_COMPLETION(name)(静态初始化)等待事件:
wait_for_completion(struct completion *x)(阻塞直到done≠0)唤醒事件:
complete(struct completion *x)(done++,唤醒1个等待进程)、complete_all(struct completion *x)(done=UINT_MAX,唤醒所有等待进程)
特点:接口极简,仅需“初始化-等待-唤醒”三步,适用于单次事件同步(如线程间通知“任务完成”)。
二、核心区别
维度 | 等待队列(Wait Queue) | 完成量(Completion) |
|---|---|---|
抽象层次 | 底层通用机制 | 高层封装(基于wait queue) |
用途 | 等待任意复杂条件(如缓冲区非空、信号到达) | 等待单一事件完成(如“操作已结束”) |
接口复杂度 | 需手动管理队列、进程状态、唤醒逻辑 | 提供 |
唤醒粒度 | 支持唤醒单个( | 支持唤醒1个( |
状态管理 | 需显式设置进程状态(如 | 内部自动处理状态(默认用 |
重复使用 | 可重复添加/删除进程,队列长期有效 | 完成后需 |
错误处理 | 可通过 |
|
三、适用场景举例
1. 用完成量(Completion)的场景
单次事件通知:如“DMA传输完成”“编码线程处理完一帧”。
例:视频采集线程采集到一帧后,用
complete()通知编码线程,编码线程用wait_for_completion()等待。struct completion frame_done; init_completion(&frame_done); // 采集线程 capture_frame(); complete(&frame_done); // 通知编码线程“帧已就绪” // 编码线程 wait_for_completion(&frame_done); // 等待帧就绪 encode_frame();简单线程同步:如主线程等待子线程初始化完成。
2. 用等待队列(Wait Queue)的场景
复杂条件等待:如“缓冲区有数据且未溢出”(生产者-消费者模型)。
例:流媒体传输线程等待“发送缓冲区有数据”,采集线程填充数据后唤醒队列。
wait_queue_head_t send_wait; init_waitqueue_head(&send_wait); char send_buf[1024]; int buf_len = 0; // 传输线程(消费者) while (1) { wait_event(send_wait, buf_len > 0); // 等待缓冲区有数据 send_data(send_buf, buf_len); buf_len = 0; } // 采集线程(生产者) buf_len = capture_to_buf(send_buf); if (buf_len > 0) wake_up(&send_wait); // 唤醒传输线程多条件等待:如同时等待“网络就绪”和“设备初始化完成”。
四、总结
完成量是简化的事件同步工具,适合“等待某事发生”的单次场景,代码简洁、开销小。
等待队列是通用的条件等待工具,适合“等待复杂条件满足”的场景,灵活性高但需手动管理。
在流媒体开发中:
若只需通知“某操作完成”(如编码结束),优先用完成量;
若需等待“多条件组合”(如缓冲区数据+网络带宽足够),则用等待队列。
两者均基于内核同步原语,理解其差异能帮助于更高效地解决流媒体 pipeline 中的同步问题(如采集-编码-显示的时序协调)。