yan_zhihui 发表于 2014-10-05 10:37

completion 与 semaphore 相比究竟有什么优点?

看了好多关于semphore completion的描述中,似乎都是要A线程 要等待 B线程工作完成后 才能继续执行。 不太理解书上为何讲使用completion 比 semaphore 更好?求指点。

daxiguagg 发表于 2014-10-05 12:30

我猜semaphore和mutex一样都是同步用的,开销应该要比completion机制大一些。

Tinnal 发表于 2014-10-07 09:48

http://stackoverflow.com/questions/4764945/difference-between-completion-variables-and-semaphores
有非常详细的说明。连引入的历史都给你了。

Tinnal 发表于 2014-10-07 09:49

There are two reasons you might want to use a completion instead of a semaphore. First, multiple threads can wait for a completion, and they can all be released with one call to complete_all(). It's more complex to have a semaphore wake up an unknown number of threads.

Second, if the waiting thread is going to deallocate the synchronization object, there is a race condition if you're using semaphores. That is, the waiter might get woken up and deallocate the object before the waking thread is done with up(). This race doesn't exist for completions. (See Lasse's post.)

Tinnal 发表于 2014-10-07 09:49

Explanation of why completions were originally implemented: http://lkml.indiana.edu/hypermail/linux/kernel/0107.3/0674.html

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.
So instead, I introduced the notion of "wait for completion":

More recent thread about completions vs semaphores http://lkml.org/lkml/2008/4/11/323

smalloc 发表于 2014-10-08 21:34

回复 4# Tinnal
That is, the waiter might get woken up and deallocate the object before the waking thread is done with up().
这句好难理解。


   

Tinnal 发表于 2014-10-08 22:04

被woken up的线程可能立即把对应的锁的空间释放,但waking 它的线程的up函数需要访问这个空间,这样就会崩溃。内核的代码里有大量的completions都是定义成局部变量的,如果改为信号量,就会出现这种情况。有个CSDN的网友也进行了说明,见:
http://blog.csdn.net/dreamxu/article/details/5866593

同时,completion比semaphore要轻量运行得快,他两个有一个本质的差别。
一个是有信号量,有数量的概论,数量不够了才睡。
一个是完成量,大家都等同一条件,没有数量的差异。

smalloc 发表于 2014-10-10 01:35

本帖最后由 smalloc 于 2014-10-10 01:38 编辑

回复 7# Tinnal


    CSDN上这个解释非常怪异,
谈的大致流程可认为:
B down 获得semaphore
A down sleep
B up start
A down
A up
B up end

也就是认为B up end 有段代码在A down up后还会去访问semaphore.

但从代码看显然不是这样。所有访问semaphore的操作都是用 spinlock_irq保护的原子操作。void up(struct semaphore *sem)
{
        unsigned long flags;

        spin_lock_irqsave(&sem->lock, flags);
        if (likely(list_empty(&sem->wait_list)))
                sem->count++;
        else
                __up(sem);
        spin_unlock_irqrestore(&sem->lock, flags);
}
这意味着从全局域角度看时序,A的down 完成也只能在B up之后

Tinnal 发表于 2014-10-10 08:49

回复 8# smalloc


技术是不断在往前发展的。要从历史的角度去看代问题,所有事情事出必有因。

引入completion时(应该是2.4.7版本)的semaphore确实存在问题,问题模型为:
http://lkml.iu.edu//hypermail/linux/kernel/0107.3/0674.html,google上应该还有其它的邮件。
那时的semaphore是没有锁保护的。到少我手上2.6.24的源码里就没有。

现在semaphore已经没有问题了。甚至有人还提议用semaphore从新实现completion:
http://lwn.net/Articles/277621/
从git来看,最终社区并没有接纳。


现在高版本的semaphore 已经不存在问题了。只是从概念层面,completion 和semaphore 应该被用来不同的场合,completion 是用来等待一个条件成力,而semaphore应该是等待一个资源。条件是没有数量的,而资源是有数量的。
从实现来说,completion更轻(我没有验正过)
请在http://www.makelinux.net/ldd3/chp-5-sect-4里搜lightweight。

老爷康 发表于 2016-04-14 17:34

这样的讨论真的很有价值 么么哒
页: [1]
查看完整版本: completion 与 semaphore 相比究竟有什么优点?