Linux Kernel Completion 使用指南
在Linux内核编程中,completion是一个用于进程同步的机制,常用于等待某个事件的完成。它提供了一种简单的方式,让一个线程等待另一个线程完成某项任务。
基本使用方法
初始化
completion结构需要在使用之前进行初始化,可以使用以下两种方式之一:
- 静态初始化:
DECLARE_COMPLETION(my_completion);
- 动态初始化:
struct completion my_completion;
init_completion(&my_completion);
等待事件
一个线程可以调用wait_for_completion
或其变种来等待事件的完成:
wait_for_completion(&my_completion);
变种方法包括:
wait_for_completion_timeout(&my_completion, timeout)
:带超时的等待。wait_for_completion_interruptible(&my_completion)
:可以被中断的等待。wait_for_completion_killable(&my_completion)
:可以被kill信号中断的等待。
触发事件
当某个事件完成时,应该调用complete
函数来唤醒等待的线程:
complete(&my_completion);
如果有多个等待者,并且你希望唤醒所有等待者,可以使用complete_all
:
complete_all(&my_completion);
高级使用方法
重新初始化
在某些情况下,一个completion结构可能需要重复使用,这时可以使用reinit_completion
重新初始化:
reinit_completion(&my_completion);
超时等待
为了避免无限期等待,可以使用带超时的等待函数,例如:
unsigned long timeout = msecs_to_jiffies(500); // 500 ms
wait_for_completion_timeout(&my_completion, timeout);
可中断的等待
有时需要等待可以被中断,可以使用wait_for_completion_interruptible
或wait_for_completion_killable
:
int ret;
ret = wait_for_completion_interruptible(&my_completion);
if (ret == -ERESTARTSYS) {// 等待被信号中断
}
注意事项
- 初始化问题:确保在使用completion之前正确初始化,避免使用未初始化的completion。
- 重入问题:避免对同一个completion结构多次调用
complete
,因为这会导致不可预测的行为。 - 超时处理:合理使用超时等待,避免线程无限期挂起。
- 中断安全:在中断上下文中不能使用可能导致睡眠的函数,例如等待函数。
- 资源释放:在模块卸载或资源释放时,确保没有线程在等待,避免资源泄漏或访问非法内存。
代码示例
以下是一个简单的例子,展示了一个线程等待另一个线程完成某项任务:
#include <linux/module.h>
#include <linux/completion.h>
#include <linux/kthread.h>
#include <linux/delay.h>static struct completion my_completion;int worker_thread(void *data) {printk(KERN_INFO "Worker thread: Starting work\n");msleep(5000); // 模拟工作printk(KERN_INFO "Worker thread: Work done, signaling completion\n");complete(&my_completion);return 0;
}static int __init my_module_init(void) {struct task_struct *task;init_completion(&my_completion);task = kthread_run(worker_thread, NULL, "worker_thread");if (IS_ERR(task)) {printk(KERN_ERR "Failed to create worker thread\n");return PTR_ERR(task);}printk(KERN_INFO "Main thread: Waiting for completion\n");wait_for_completion(&my_completion);printk(KERN_INFO "Main thread: Detected completion\n");return 0;
}static void __exit my_module_exit(void) {printk(KERN_INFO "Module exit\n");
}module_init(my_module_init);
module_exit(my_module_exit);MODULE_LICENSE("GPL");
这个例子创建了一个工作线程,该线程在完成工作后调用complete
。主线程等待工作线程完成后继续执行。
总结
Linux内核中的completion机制是一个强大的工具,用于线程间的同步。通过合理使用它,可以有效地控制线程的执行顺序,确保程序的正确性。在使用时,应注意初始化、超时、中断安全等问题,以避免潜在的bug。