把线程池待处理工作按 FIFO 交给 worker
QEMU 线程池用尾队列组织待处理请求:提交时尾插,worker 持锁从头部领取,然后在锁外执行工作。
相关概念
工程问题#
AioContext 需要把会阻塞的工作交给后台线程,同时让多个 worker 安全领取不同请求,并把完成通知送回事件循环。
实际实现#
thread_pool_submit_aio 对 request_list 执行 QTAILQ_INSERT_TAIL;worker_thread 取 QTAILQ_FIRST 并移除,更新状态后解锁执行。完成状态通过内存屏障与 bottom half 通知衔接。
处理流程#
- 创建请求并标记为 THREAD_QUEUED
- 持锁把请求放到队尾并唤醒 worker
- worker 持锁领取队头并在锁外执行
- 记录结果并安排完成通知
源码片段#
固定版本 · 原文摘录util/thread-pool.cv9.2.0 · L106–L119
106 req = QTAILQ_FIRST(&pool->request_list);107 QTAILQ_REMOVE(&pool->request_list, req, reqs);108 req->state = THREAD_ACTIVE;109 qemu_mutex_unlock(&pool->lock);110111 ret = req->func(req->arg);112113 req->ret = ret;114 /* Write ret before state. */115 smp_wmb();116 req->state = THREAD_DONE;117118 qemu_bh_schedule(pool->completion_bh);119 qemu_mutex_lock(&pool->lock);worker_thread
worker 在已持有 pool->lock 的上下文中领取并摘除队头,随后释放锁执行函数。尾插证据在同文件第 265 行;此片段同时说明线程并行执行与 FIFO 领取并不等同于 FIFO 完成。
连续摘录 worker 循环的领取与执行分支;完整文件保留其加锁、等待和提交端尾插的上下文。
收益与取舍#
工程分析带来的收益
- 队尾插入与队头摘除不需要扫描待处理集合
- 锁外执行工作避免整个任务期间占用队列锁
付出的代价
- 工程分析:共享队列锁在高并发时可能形成竞争
- FIFO 领取不代表开始执行或完成回调严格同序
可比较的选择
有界环形队列可紧凑存放任务,但需要明确容量耗尽策略,任意取消已排队请求也更难处理。
版本与适用范围#
对应 QEMU v9.2.0 通用线程池的 request_list,不是所有 QEMU I/O 的统一队列。取消可移除尚未领取的请求;多 worker 会并行运行,因此只按队列出队顺序解释 FIFO。
参考来源#
源码、官方文档与原始论文相关实现与比较#
1 个相关案例Linux IIO 的 kfifo 缓冲在采样进入内核与用户态读取之间暂存数据,按先进先出顺序交付采样记录。
附源码片段 · 内存管理