完成量同步机制学习(2.6.23)
来源:互联网 发布:全局最优解算法 编辑:程序博客网 时间:2024/04/29 21:07
一、定义: linux/include/linux/completion.h 二、作用: 虽然信号量可以用于实现同步,但往往可能会出现一些不好的结果。例如:当进程A分配了一个临时信号量变量,把它初始化为关闭的MUTEX,并把其地址传递给进程B,然后在A之上调用down(),进程A打算一旦被唤醒就撤销给信号量。随后,运行在不同CPU上的进程B在同一个信号量上调用up()。然而,up()和down()的目前实现还允许这两个函数在同一个信号量上并发。因此,进程A可以被唤醒并撤销临时信号量,而进程B还在运行up()函数。结果up()可能试图访问一个不存在的数据结构。这样就会出现错误。为了防止发生这种错误就专门设计了completion机制专门用于同步。 三、个字段详解: 1、unsigned int done; 指示等待的事件是否完成。初始化时为0。如果为0,则表示等待的事件未完成。大于0表示等待的事件已经完成。 2、wait_queue_head_t wait; 存放等待该事件完成的进程队列。 四、操作: 1、定义和初始化: (1) struct completion completion; init_completion(&completion); 直接定义并调用init_completion()初始化。init_completion()会将done字段初始化为0,wait字段的自旋锁为未锁,等待队列为空。这说明调用该完成量的进程必须等待某事件完成(即另外一进程必须先调用completiom()唤醒该完成量)。 (2) DECLARE_COMPLETION(completion); 直接定义并初始化completion完成量,效果等同于以上定义方式。 2、等待完成量: (1)wait_for_completion()函数,/linux/kernel/sched.c 该函数相当于信号量中的down()操作。不过在操作中对使用其自身的自旋锁。如果done为0,则说明等待的事件没有完成,则调用DECLARE_WAITQUEUE()定义等待队列wait并将当前进程添加进等待队列wait。然后将wait添加进该完成量的等待队列的末尾,进入循环。设置当前进程为不可中断状态(TASK_UNINTERRUPTIBLE),释放自旋锁并让当前进程进入睡眠状态。一旦进程被调度唤醒据又获得自旋锁并查看等待的事件是否完成。如果完成(大于0),则从完成量的等待队列中删除等待的进程,并自减 done ,释放自旋锁,从等待状态返回继续运行。否则继续睡眠。如果done于大0,则说明等待的事件已经完成,则自减done,直接返回。 (2)wait_for_completion_timeout()函数,/linux/kernel/sched.c 也是等待完成量。与wait_for_completion()最大的区别是它等待超时的情况下返回。也就是说如果经过给定的时间该完成量还没有被唤醒,就直接返回。这样最大的好处是经过一定的时间该进程已经不需要等待某事件,那么就可以直接被唤醒继续执行。 (3)wait_for_completion_interruptible()函数,/linux/kernel/sched.c 可见这中等待完成量的方式是可以被信号打断的。如果当前进程收到 如果收到TIF_SIGPENDING信号,则等待该完成量的进程会被从等待队列中删除,并返回ERESTARTSYS。 (4)wait_for_completion_interruptible_timeout()函数,/linux/kernel/sched.c 3、唤醒完成量: (1)completion()函数:/linux/kernel/sched.c (2)completion_all()函数:/linux/kernel/sched.c 13struct completion { 14 unsigned int done; 15 wait_queue_head_t wait; 16};
3731void fastcall __sched wait_for_completion(struct completion *x)3732{3733 might_sleep();37343735 spin_lock_irq(&x->wait.lock);3736 if (!x->done) {3737 DECLARE_WAITQUEUE(wait, current);37383739 wait.flags |= WQ_FLAG_EXCLUSIVE;3740 __add_wait_queue_tail(&x->wait, &wait);3741 do {3742 __set_current_state(TASK_UNINTERRUPTIBLE);3743 spin_unlock_irq(&x->wait.lock);3744 schedule();3745 spin_lock_irq(&x->wait.lock);3746 } while (!x->done);3747 __remove_wait_queue(&x->wait, &wait);3748 }3749 x->done--;3750 spin_unlock_irq(&x->wait.lock);3751}
3754unsigned long fastcall __sched3755wait_for_completion_timeout(struct completion *x, unsigned long timeout)3756{3757 might_sleep();37583759 spin_lock_irq(&x->wait.lock);3760 if (!x->done) {3761 DECLARE_WAITQUEUE(wait, current);37623763 wait.flags |= WQ_FLAG_EXCLUSIVE;3764 __add_wait_queue_tail(&x->wait, &wait);3765 do {3766 __set_current_state(TASK_UNINTERRUPTIBLE);3767 spin_unlock_irq(&x->wait.lock);3768 timeout = schedule_timeout(timeout);3769 spin_lock_irq(&x->wait.lock);3770 if (!timeout) {3771 __remove_wait_queue(&x->wait, &wait);3772 goto out;3773 }3774 } while (!x->done);3775 __remove_wait_queue(&x->wait, &wait);3776 }3777 x->done--;3778out:3779 spin_unlock_irq(&x->wait.lock);3780 return timeout;3781}
3784int fastcall __sched wait_for_completion_interruptible(struct completion *x)3785{3786 int ret = 0;37873788 might_sleep();37893790 spin_lock_irq(&x->wait.lock);3791 if (!x->done) {3792 DECLARE_WAITQUEUE(wait, current);37933794 wait.flags |= WQ_FLAG_EXCLUSIVE;3795 __add_wait_queue_tail(&x->wait, &wait);3796 do {3797 if (signal_pending(current)) {3798 ret = -ERESTARTSYS;3799 __remove_wait_queue(&x->wait, &wait);3800 goto out;3801 }3802 __set_current_state(TASK_INTERRUPTIBLE);3803 spin_unlock_irq(&x->wait.lock);3804 schedule();3805 spin_lock_irq(&x->wait.lock);3806 } while (!x->done);3807 __remove_wait_queue(&x->wait, &wait);3808 }3809 x->done--;3810out:3811 spin_unlock_irq(&x->wait.lock);38123813 return ret;3814}
3817unsigned long fastcall __sched3818wait_for_completion_interruptible_timeout(struct completion *x,3819 unsigned long timeout)3820{3821 might_sleep();38223823 spin_lock_irq(&x->wait.lock);3824 if (!x->done) {3825 DECLARE_WAITQUEUE(wait, current);38263827 wait.flags |= WQ_FLAG_EXCLUSIVE;3828 __add_wait_queue_tail(&x->wait, &wait);3829 do {3830 if (signal_pending(current)) {3831 timeout = -ERESTARTSYS;3832 __remove_wait_queue(&x->wait, &wait);3833 goto out;3834 }3835 __set_current_state(TASK_INTERRUPTIBLE);3836 spin_unlock_irq(&x->wait.lock);3837 timeout = schedule_timeout(timeout);3838 spin_lock_irq(&x->wait.lock);3839 if (!timeout) {3840 __remove_wait_queue(&x->wait, &wait);3841 goto out;3842 }3843 } while (!x->done);3844 __remove_wait_queue(&x->wait, &wait);3845 }3846 x->done--;3847out:3848 spin_unlock_irq(&x->wait.lock);3849 return timeout;3850}
可中断的并且可超时返回的等待完成量。
3707void fastcall complete(struct completion *x)3708{3709 unsigned long flags;37103711 spin_lock_irqsave(&x->wait.lock, flags);3712 x->done++;3713 __wake_up_common(&x->wait, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE,3714 1, 0, NULL);3715 spin_unlock_irqrestore(&x->wait.lock, flags);3716
用于唤醒一个等待该完成量的进程。
3719void fastcall complete_all(struct completion *x)3720{3721 unsigned long flags;37223723 spin_lock_irqsave(&x->wait.lock, flags);3724 x->done += UINT_MAX/2;3725 __wake_up_common(&x->wait, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE,3726 0, 0, NULL);3727 spin_unlock_irqrestore(&x->wait.lock, flags);3728
唤醒所有等待给完成量的进程。
- 完成量同步机制学习(2.6.23)
- 完成量同步机制学习
- 内核同步机制——完成量
- 线程间同步机制之完成量
- 完成量:线程同步
- 完成量实现线程同步
- linux中同步例子(完成量completion)
- linux中同步例子(完成量completion)
- linux中同步例子(完成量completion…
- linux中同步例子(完成量completion…
- 大话Linux内核中锁机制之完成量、互斥量
- 大话Linux内核中锁机制之完成量、互斥量
- Linux内核中锁机制之完成量、互斥量
- Linux内核中锁机制之完成量、互斥量
- 大话Linux内核中锁机制之完成量、互斥量
- 内核同步机制之信号量&读写信号量&完成变量
- Java学习 - synchronized同步机制
- 解决图随机上传,不限量,定位置,与文章进库同步完成
- Magento深入
- 生成基于linux的乐教电视播放列表
- 自定义回调函数
- 9种方法让你的网站更加社会化
- java中double型数据的加减乘除
- 完成量同步机制学习(2.6.23)
- C#DateTime时间与JS Date时间的相互转化(C#后台)
- plsql 实现md5
- 游戏引擎基础
- AS知识点总结
- 字符格式数字?
- ecshop表简介
- CentOs5.4 Grass 安装 操作过程
- 火狐网页打开为什么那么慢?有什么解决办法吗?