Linux内核中的Completion机制:同步等待的艺术

张开发
2026/4/5 20:04:26 15 分钟阅读

分享文章

Linux内核中的Completion机制:同步等待的艺术
Linux内核中的Completion机制同步等待的艺术作为一名深耕操作系统和嵌入式开发的工程师我对Linux内核中的Completion机制有着深入的理解。Completion是一种轻量级的同步原语用于一个线程等待另一个线程完成某个操作。Completion的基本概念Completion机制的核心思想是单次信号一旦完成所有等待者都会被唤醒无需锁不需要额外的锁来保护状态内存效率高只需要一个结构体即可实现Completion的核心API1. 初始化和销毁// 静态初始化 DECLARE_COMPLETION(my_completion); // 动态初始化 struct completion my_completion; init_completion(my_completion); // 重新初始化可重复使用 reinit_completion(my_completion);2. 等待完成// 无限期等待 wait_for_completion(my_completion); // 带超时等待 long timeout wait_for_completion_timeout(my_completion, msecs_to_jiffies(1000)); if (timeout 0) { // 超时 } // 可中断等待 int ret wait_for_completion_interruptible(my_completion); if (ret -ERESTARTSYS) { // 被信号中断 } // 可中断且带超时 int ret wait_for_completion_interruptible_timeout(my_completion, msecs_to_jiffies(1000));3. 完成信号// 唤醒一个等待者 complete(my_completion); // 唤醒所有等待者 complete_all(my_completion);Completion的实现原理struct completion { unsigned int done; wait_queue_head_t wait; }; // 等待实现 void wait_for_completion(struct completion *x) { wait_queue_t wait; spin_lock_irq(x-wait.lock); if (!x-done) { // 添加到等待队列 __add_wait_queue_tail(x-wait, wait); // 睡眠等待 do_wait(); } else { x-done--; } spin_unlock_irq(x-wait.lock); } // 完成信号实现 void complete(struct completion *x) { unsigned long flags; spin_lock_irqsave(x-wait.lock, flags); x-done; __wake_up_locked(x-wait, TASK_NORMAL, 1); spin_unlock_irqrestore(x-wait.lock, flags); }使用场景1. 模块加载等待static struct completion module_loaded; static int __init my_module_init(void) { init_completion(module_loaded); // 创建工作线程 kthread_run(worker_thread, NULL, my_worker); // 等待工作线程初始化完成 wait_for_completion(module_loaded); return 0; } static int worker_thread(void *data) { // 初始化工作 do_initialization(); // 通知初始化完成 complete(module_loaded); // 继续执行 while (!kthread_should_stop()) { do_work(); } return 0; }2. 异步I/O完成通知struct async_io { struct completion done; int result; }; int async_read(struct file *file, void *buf, size_t count) { struct async_io io; init_completion(io.done); // 提交异步I/O请求 submit_async_request(file, buf, count, io_complete_callback, io); // 等待I/O完成 wait_for_completion(io.done); return io.result; } void io_complete_callback(void *private, int result) { struct async_io *io private; io-result result; complete(io-done); }3. 多阶段初始化struct init_stage { struct completion stage1_done; struct completion stage2_done; struct completion stage3_done; }; void multi_stage_init(struct init_stage *stage) { init_completion(stage-stage1_done); init_completion(stage-stage2_done); init_completion(stage-stage3_done); // 启动阶段1 kthread_run(stage1_worker, stage, stage1); wait_for_completion(stage-stage1_done); // 启动阶段2 kthread_run(stage2_worker, stage, stage2); wait_for_completion(stage-stage2_done); // 启动阶段3 kthread_run(stage3_worker, stage, stage3); wait_for_completion(stage-stage3_done); }与信号量和锁的对比特性Completion信号量互斥锁用途一次性事件资源计数互斥访问可重复使用是需reinit是是等待者数量多个多个多个典型场景初始化完成资源池临界区保护性能优化建议避免在热路径使用Completion适合初始化等冷路径合理设置超时防止无限期等待处理中断情况使用可中断版本处理信号注意完成顺序确保complete在wait之后调用总结Completion是Linux内核中简洁高效的同步机制特别适合初始化完成通知、异步操作等待等场景。作为嵌入式开发者合理使用Completion可以简化同步逻辑提高代码可读性。

更多文章