Linux的completions同步机制

1. 什么是completions机制?

在内核编程中常有这样的场景,在当前线程中创建一个线程,并且等待它完成之后再继续执行。通常可以用信号量来解决它,也可以用completion机制来解决。

2. 为什么用completions ,它比信号量好在哪?

使用completion比使用信号量简单。

使用completion可以一次性唤醒所有等待进程,而用信号量会比较麻烦。

 The basic summary is that we had this (fairly common) way of waiting for certain events by having a locked semaphore on the stack of the waiter, and then having the waiter do a "down()" which caused it to block until the thing it was waiting for did an "up()".

This works fairly well, but it has a really small (and quite unlikely) race on SMP, that is not so much a race of the idea itself, as of the implementation of the semaphores. We could have fixed the semaphores, but there were a few reasons not to:

  • the semaphores are optimized (on purpose) for the non-contention case. The "wait for completion" usage has the opposite default case
  • the semaphores are quite involved and architecture-specific, exactly
    due to this optimization. Trying to change them is painful as hell.

 

Completions

A common pattern in kernel programming involves initiating some activity outside of the current thread, then waiting for that activity to complete. This activity can be the creation of a new kernel thread or user-space process, a request to an existing process, or some sort of hardware-based action. It such cases, it can be tempting to use a semaphore for synchronization of the two tasks, with code such as:

struct semaphore sem;

init_MUTEX_LOCKED(&sem);
start_external_task(&sem);
down(&sem);

The external task can then call up(&sem) when its work is done.

As is turns out, semaphores are not the best tool to use in this situation. In normal use, code attempting to lock a semaphore finds that semaphore available almost all the time; if there is significant contention for the semaphore, performance suffers and the locking scheme needs to be reviewed. So semaphores have been heavily optimized for the "available" case. When used to communicate task completion in the way shown above, however, the thread calling down will almost always have to wait; performance will suffer accordingly. Semaphores can also be subject to a (difficult) race condition when used in this way if they are declared as automatic variables. In some cases, the semaphore could vanish before the process calling up is finished with it.

 

3. 怎么用completions?

 

/*
 * Completions 目前使用先进先出的队列来存放等待‘completion’的事件
 */
struct completion {
        unsigned int done;
        wait_queue_head_t wait;
};

 

 

    
    (1) 定义completion
        struct completion my_completion;
    (2) 初始化completion
        init_completion(&my_completion);/*动态创建一个completion*/
		
        DECLEARE_COMPLETION(my_completion);/*(包含定义)静态初始化completion*/
		
    (3) 等待completion
	/*This waits to be signaled for completion of a specific task. It is NOT interruptible and there is no timeout.*/
	void wait_for_completion(struct completion *c);
	/*This waits for completion of a specific task to be signaled. It is interruptible.*/
	int wait_for_completion_interruptible(struct completion *x); 
	/*This waits to be signaled for completion of a specific task. It can be
	* interrupted by a kill signal.
	*/
	int wait_for_completion_killable(struct completion *x);
		
	/*This waits for either a completion of a specific task to be signaled or for a
	* specified timeout to expire. The timeout is in jiffies. It is not
	* interruptible.
	*/
	unsigned long wait_for_completion_timeout(struct completion *x,
							   unsigned long timeout);
	/** This waits for either a completion of a specific task to be signaled or for a
	* specified timeout to expire. It is interruptible. The timeout is in jiffies.
	*/
	long wait_for_completion_interruptible_timeout(
				struct completion *x, unsigned long timeout);
	/*This waits for either a completion of a specific task to be
	* signaled or for a specified timeout to expire. It can be
	* interrupted by a kill signal. The timeout is in jiffies.
	*/
	long wait_for_completion_killable_timeout(
				struct completion *x, unsigned long timeout);
    (4) 唤醒completion
        void complete(struct completion *c);/*唤醒一个等待的Thread*/
        void complete_all(struct completion *c);/*唤醒所有等待此completion的Threads*/


[1] http://stackoverflow.com/questions/4764945/difference-between-completion-variables-and-semaphores

[2] http://www.makelinux.net/ldd3/chp-5-sect-4

[3] http://blog.csdn.net/dreamxu/article/details/5866593 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值