Linux driver:completion

在Linux下用于防止竞争的机制包括:信号量,completion,自旋锁

**completion,本质上是一个计数器,**主要用于线程之间的同步。当线程调用wait_for_completion(及其类似函数)检测该计数器为0时,被阻塞,否则往下执行。当一个线程完成工作时,调用complete(_all),增加计数器的值,这样可以唤醒阻塞的线程。注意,complete_all会将计数器设置为一个很大的值(UINT_MAX/2),因此确定没有线程被阻塞后,可以调用reinit_completion重置计数器。

在Linux内核中,completion是一种简单的同步机制,标志"things may proceed"。

要使用completion,必须在文件中包含<linux/completion.h>,同时创建一个类型为struct completion的变量。

这个变量可以静态地声明和初始化:  
DECLARE_COMPLETION(my_comp);  
或者动态初始化:  
struct completion my_comp;  
init_completion(&my_comp);  

如果驱动程序要在执行后面操作之前等待某个过程的完成,它可以调用wait_for_completion ,以要完成的事件为参数:

void wait_for_completion(struct completion *comp);  

wait_for_completion等待在completion上。如果加了interruptible,就表示线程等待可被外部发来的信号打断;如果加了killable,就表示线程只可被kill信号打断;如果加了timeout,表示等待超出一定时间会自动结束等待,timeout的单位是系统所用的时间片jiffies(多为1ms)。

如果其它部分代码可以确定事件已经完成,可以调用下面两个函数之一来唤醒等待该事件的进程:

void complete(struct completion *comp);  
void complete_all(struct completion *comp); /* Linux 2.5.x以上版本 */  

前一个函数将只唤醒一个等待进程,而后一个函数唤醒等待该事件的所以进程。由于completion的实现方式,即使complete在wait_for_competion之前调用,也可以正常工作。
例如,在MD设备驱动程序实现中,有一个恢复线程md_recovery_thread。驱动程序通过md_register_thread和md_unregister_thread来注册和注销恢复线程。恢复线程的执行逻辑在md_thread函数中,大致如下:

int md_thread(void * arg)  
{  
    线程初始化;  
    while (运行) {  
        处理逻辑;  
        接收信号;  
    }  
    return 0;  
}  

md_register_thread将创建一个恢复线程,它必须在线程真正初始化结束之后才能返回该线程的指针。因此,其逻辑是:

mdk_thread_t *md_register_thread(void (*run) (void *), void *data, const char *name)  
{  
    mdk_thread_t *thread;  
    ……  
    struct completion event;  
    /* 为线程分配空间 */  
    thread = (mdk_thread_t *) kmalloc (sizeof(mdk_thread_t), GFP_KERNEL);  
    ……  
    init_completion(&event);  
    ……  
    thread->event = &event;  
    /* 创建内核线程 */  
    ret = kernel_thread(md_thread, thread, 0);  
    /* 等待线程初始化结束 */  
    ……  
    wait_for_completion(&event);  
    /* 返回线程指针 */  
    return thread;  
}  

而md_unregister_thread通过向线程发送SIGKILL信号注销恢复线程,它也需要在线程真正退出后才能释放线程所占用的内存。因此,其逻辑是:

void md_unregister_thread(mdk_thread_t *thread)  
{  
    struct completion event;  
    init_completion(&event);  
    thread->event = &event;  
    ……  
    /* 向线程发送SIGKILL信号终止其运行 */  
    md_interrupt_thread(thread);  
    /* 等待线程退出 */  
    wait_for_completion(&event);  
    /* 释放线程所占用的内存 */  
    kfree(thread);  
}  

如果考虑completion,md_thread的逻辑是:

int md_thread(void * arg)  
{  
    线程初始化;  
    complete(thread->event);   
    while (运行) {  
        处理逻辑;  
        接收信号;  
    }  
    complete(thread->event);   
    return 0;  
}  

需要说明的是,由于等待事件是在驱动程序和恢复线程中的一个共享资源,它必须是一个全局变量,或者如实现代码中,定义为一个局部变量,而将其指针放在恢复线程结构中。
typedef struct mdk_thread_s {
……
struct completion *event;
……
} mdk_thread_t;

转:https://blog.csdn.net/liuxd3000/article/details/17912695

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_kerneler

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值