设备驱动中的并发控制-完成量

参考:《Linux驱动开发入门与实战》

        Linux中提供了一种机制,实现一个线程发送一个信号通知另一个线程已完成某个任务,这种机制就是完成量。完成量的目的是告诉一个线程某事件已经发生,可以在此事件基础上做你想做的另一个事件。

1. 完成量的实现

        完成量是实现两个任务之间同步的简单方法,在内核中完成量由struct completion结构体表示。该结构体定义在include\linux\completion.h文件中,其定义如下所示:

        struct completion{

                unsigned int done;

                wait_queue_head_t wait;

        };

        done成员

        done成员维护一个计数。当初始化一个完成量时,done成员被初始化为1。当done等于0时,会将拥有完成量的线程置于等待状态;当done的值大于0时,表示等待完成量的函数可以立刻执行。

        wait成员

        wait是一个等待队列的链表头,这个链表将所有等待该完成量的进程组成一个链表结构。在这个链表中,存放了正在睡眠的进程链表。

2. 完成量的使用

        在Linux中,完成量的类型为struct completion。内核提供了一系列的函数对struct completion进行操作。

​​​​​​​​​​​​​​2.1 定义和初始化完成量

        struct completion com;

        一个完成量必须初始化才能被使用,init_completion()函数用来初始化完成量。其定义如下:

static inline void init_completion(struct completion *x)

{

    x->done = 0;

    init_waitqueue_head(&x->wait);   /* 初始化等待队列头 */

}

        还可以使用宏DECLARE_COMPLETION定义和初始化一个完成量,定义如下:

        #define DECLARE_COMPLETION(work) \

        struct completion work = COMPLETION_INITIALIZER(work)

        #define COMPLETION_INITIALIZER(work) \

        {0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait)}

        这个宏与init_completion()函数实现的功能一样,只是定义和初始化一个完成量的简单实现而已。

2.2 等待完成量

        当要实现同步时,可以使用wait_for_completion()函数等待一个完成量。代码如下:

        void __sched wait_for_completion(struct completion *x);

        该函数会执行一个不会被信号中断的等待。如果调用这个函数之后,没有一个线程完成这个完成量,那么执行wait_for_completion()函数的线程会一直等待下去,线程将不可以退出。

2.3 释放完成量

    当需要同步的任务完成后,可以使用下面两个函数唤醒完成量。当唤醒之后,wait_for_completion()函数之后的代码才可以继续执行。这两个函数定义如下:

        void complete(struct completion *x);

        void complete_all(struct completion *x);

2.4 使用完成量

        以下是完成量的使用方法:

struct completion com; /* 定义完成量 */
int xxx_init(void)
{
    ...
    init_completion(&com);  /* 初始化完成量 */
    ...
}
int xxx_A()
{
    ...
    /* 代码A */
    wait_for_completion(&com);  /* 申请完成量 */
    /* 代码B */
    ...
    return 0;
}
int xxx_B()
{
    ...
    /* 代码C */
    complete(&com);   /* 释放完成量 */
    ...
}

        代码中,xxx_init()函数完成了完成量的初始化。在xxx_A()函数中代码会一直执行到wait_for_completion()函数,如果此时com->done的值等于0,那么线程会进入睡眠。如果此时的值大于0,那么wait_for_completion()函数将com->done的值减去1,然后执行代码B部分。

        在执行xxx_B()函数的过程中,无论如何代码C都可以顺利执行,complete()函数会将com->done的值加1,然后唤醒com->wait中的一个线程。如果碰巧这个线程是执行xxx_A()函数的线程,那么会将这个线程从com->wait队列中唤醒并执行。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值