Linux内核中completion的使用
completion是Linux内核中用于线程间同步的一种机制,它允许一个线程告诉另一个线程某个特定事件已经完成。下面详细介绍completion的使用方法。
基本概念
completion机制用于解决以下场景:
-
一个线程需要等待另一个线程完成某项工作
-
需要比信号量更轻量级的同步机制
-
需要明确的完成通知而非状态查询
使用方法
1. 定义和初始化completion
#include <linux/completion.h>
// 静态定义并初始化
DECLARE_COMPLETION(my_completion);
// 动态初始化
struct completion my_completion;
init_completion(&my_completion);
2. 等待completion
// 无限等待
void wait_for_completion(struct completion *c);
// 可中断的等待(可能被信号打断)
int wait_for_completion_interruptible(struct completion *c);
// 带超时的等待(返回剩余时间,0表示超时)
unsigned long wait_for_completion_timeout(struct completion *c, unsigned long timeout);
// 可中断且带超时的等待
long wait_for_completion_interruptible_timeout(struct completion *c, unsigned long timeout);
3. 触发completion
// 唤醒一个等待者
void complete(struct completion *c);
// 唤醒所有等待者
void complete_all(struct completion *c);
4. 重新初始化completion
// 重新初始化completion(通常在complete_all之后使用)
reinit_completion(&my_completion);
使用示例
简单示例
DECLARE_COMPLETION(comp);
// 线程1
void thread1(void)
{
// 做一些工作
do_some_work();
// 通知完成
complete(&comp);
}
// 线程2
void thread2(void)
{
// 等待工作完成
wait_for_completion(&comp);
// 继续执行
continue_work();
}
带超时的示例
struct completion done;
unsigned long timeout = msecs_to_jiffies(1000); // 1秒超时
init_completion(&done);
// 启动工作线程
start_work_thread(&done);
// 主线程等待
if (!wait_for_completion_timeout(&done, timeout)) {
// 超时处理
pr_err("Operation timed out\n");
} else {
// 正常完成
pr_info("Operation completed\n");
}
注意事项
-
不要滥用complete_all:除非确实需要唤醒所有等待者,否则使用complete()更合适
-
内存屏障:completion机制包含内存屏障,确保操作的可见性
-
不可重复使用:除非调用reinit_completion(),否则completion只能触发一次
-
资源释放:确保在模块退出时没有线程在等待completion
与信号量的比较
completion相比信号量有以下特点:
-
更明确的语义("完成"而非"可用")
-
更高效的实现
-
专为一次性事件设计
-
内置内存屏障
completion机制在内核中广泛使用,特别是在设备驱动和子系统的初始化过程中。
877

被折叠的 条评论
为什么被折叠?



