Linux内核 -- 多线程之完成量completion的使用

Linux Kernel Completion 使用指南

在Linux内核编程中,completion是一个用于进程同步的机制,常用于等待某个事件的完成。它提供了一种简单的方式,让一个线程等待另一个线程完成某项任务。

基本使用方法

初始化

completion结构需要在使用之前进行初始化,可以使用以下两种方式之一:

  1. 静态初始化:
DECLARE_COMPLETION(my_completion);
  1. 动态初始化:
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_interruptiblewait_for_completion_killable

int ret;
ret = wait_for_completion_interruptible(&my_completion);
if (ret == -ERESTARTSYS) {
    // 等待被信号中断
}

注意事项

  1. 初始化问题:确保在使用completion之前正确初始化,避免使用未初始化的completion。
  2. 重入问题:避免对同一个completion结构多次调用complete,因为这会导致不可预测的行为。
  3. 超时处理:合理使用超时等待,避免线程无限期挂起。
  4. 中断安全:在中断上下文中不能使用可能导致睡眠的函数,例如等待函数。
  5. 资源释放:在模块卸载或资源释放时,确保没有线程在等待,避免资源泄漏或访问非法内存。

代码示例

以下是一个简单的例子,展示了一个线程等待另一个线程完成某项任务:

#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。

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值