Chinaunix首页 | 论坛 | 博客
  • 博客访问: 968869
  • 博文数量: 113
  • 博客积分: 7235
  • 博客等级: 少将
  • 技术积分: 2101
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-14 11:24
文章分类

全部博文(113)

文章存档

2013年(7)

2012年(5)

2011年(6)

2010年(8)

2009年(15)

2008年(72)

分类: LINUX

2008-08-01 21:55:15

一、定义:

linux/include/linux/completion.h

struct  {
        unsigned int ;
         ;
};

二、作用:

虽然信号量可以用于实现同步,但往往可能会出现一些不好的结果。例如:当进程A分配了一个临时信号量变量,把它初始化为关闭的MUTEX,并把其地址传递给进程B,然后在A之上调用down(),进程A打算一旦被唤醒就撤销给信号量。随后,运行在不同CPU上的进程B在同一个信号量上调用up()。然而,up()down()的目前实现还允许这两个函数在同一个信号量上并发。因此,进程A可以被唤醒并撤销临时信号量,而进程B还在运行up()函数。结果up()可能试图访问一个不存在的数据结构。这样就会出现错误。为了防止发生这种错误就专门设计了completion机制专门用于同步。

三、个字段详解:

1unsigned int done;

指示等待的事件是否完成。初始化时为0。如果为0,则表示等待的事件未完成。大于0表示等待的事件已经完成。

2wait_queue_head_t wait;

存放等待该事件完成的进程队列。

四、操作:

1、定义和初始化:

(1)

struct completion completion;

init_completion(&completion);

直接定义并调用init_completion()初始化。init_completion()会将done字段初始化为0wait字段的自旋锁为未锁,等待队列为空。这说明调用该完成量的进程必须等待某事件完成(即另外一进程必须先调用completiom()唤醒该完成量)

(2)

DECLARE_COMPLETION(completion);

直接定义并初始化completion完成量,效果等同于以上定义方式。

2、等待完成量:

(1)wait_for_completion()函数,/linux/kernel/sched.c

void   (struct  *)
{
        ();

        (&->.);
        if (!->) {
                (, current);

                . |= ;
                (&->, &);
                do {
                        __set_current_state();
                        (&->.);
                        ();
                        (&->.);
                } while (!->);
                (&->, &);
        }
        ->--;
        (&->.);
}

该函数相当于信号量中的down()操作。不过在操作中对使用其自身的自旋锁。如果done0,则说明等待的事件没有完成,则调用DECLARE_WAITQUEUE()定义等待队列wait并将当前进程添加进等待队列wait。然后将wait添加进该完成量的等待队列的末尾,进入循环。设置当前进程为不可中断状态(TASK_UNINTERRUPTIBLE),释放自旋锁并让当前进程进入睡眠状态。一旦进程被调度唤醒据又获得自旋锁并查看等待的事件是否完成。如果完成(大于0),则从完成量的等待队列中删除等待的进程,并自减 done ,释放自旋锁,从等待状态返回继续运行。否则继续睡眠。如果done于大0,则说明等待的事件已经完成,则自减done,直接返回。

(2)wait_for_completion_timeout()函数,/linux/kernel/sched.c

unsigned long  
(struct  *, unsigned long )
{
        ();

        (&->.);
        if (!->) {
                (, current);

                . |= ;
                (&->, &);
                do {
                        __set_current_state();
                        (&->.);
                         = ();
                        (&->.);
                        if (!) {
                                (&->, &);
                                goto ;
                        }
                } while (!->);
                (&->, &);
        }
        ->--;
:
        (&->.);
        return ;
}

也是等待完成量。与wait_for_completion()最大的区别是它等待超时的情况下返回。也就是说如果经过给定的时间该完成量还没有被唤醒,就直接返回。这样最大的好处是经过一定的时间该进程已经不需要等待某事件,那么就可以直接被唤醒继续执行。

(3)wait_for_completion_interruptible()函数,/linux/kernel/sched.c

int   (struct  *)
{
        int  = 0;

        ();

        (&->.);
        if (!->) {
                (, current);

                . |= ;
                (&->, &);
                do {
                        if ((current)) {
                                 = -;
                                (&->, &);
                                goto ;
                        }
                        __set_current_state();
                        (&->.);
                        ();
                        (&->.);
                } while (!->);
                (&->, &);
        }
        ->--;
:
        (&->.);

        return ;
}

可见这中等待完成量的方式是可以被信号打断的。如果当前进程收到 如果收到TIF_SIGPENDING信号,则等待该完成量的进程会被从等待队列中删除,并返回ERESTARTSYS

(4)wait_for_completion_interruptible_timeout()函数,/linux/kernel/sched.c

unsigned long  
(struct  *,
                                          unsigned long )
{
        ();

        (&->.);
        if (!->) {
                (, current);

                . |= ;
                (&->, &);
                do {
                        if ((current)) {
                                 = -;
                                (&->, &);
                                goto ;
                        }
                        __set_current_state();
                        (&->.);
                         = ();
                        (&->.);
                        if (!) {
                                (&->, &);
                                goto ;
                        }
                } while (!->);
                (&->, &);
        }
        ->--;
:
        (&->.);
        return ;
}

可中断的并且可超时返回的等待完成量。

3、唤醒完成量:

(1)completion()函数:/linux/kernel/sched.c

void  (struct  *)
{
        unsigned long ;

        (&->., );
        ->++;
        (&->,  | ,
                         1, 0, );
        (&->., );

用于唤醒一个等待该完成量的进程。

(2)completion_all()函数:/linux/kernel/sched.c

void  (struct  *)
{
        unsigned long ;

        (&->., );
        -> += /2;
        (&->,  | ,
                         0, 0, );
        (&->., );

唤醒所有等待给完成量的进程。



阅读(4231) | 评论(3) | 转发(1) |
给主人留下些什么吧!~~

KYlinux2008-08-03 17:22:18

完成量是信号量的一种简单机制,是使两个任务得以同步的简单方法。如果一个 任务时,另个任务就在等待队列中等待。

kylinux2008-08-03 16:57:07

看的有点不明白,具体同步是怎样实现的 能不能举个例子

chinahhucai2008-08-02 15:44:52

我也可以改变up()和down()的实现以禁止在同一信号量上并发执行,为什么要将信号量初始化为关闭的MUTEX呢?当然,我们可能会说这样改变可能需要另外的指令,对于频繁使用的函数来说不是什么好事.这又是为什么呢? 在2.等待完成量下面的几个函数中,核心的函数是wait_for_completion(),如果能够将这个函数弄明白,那么接下去的几个也就是增加一点点功能而已.