semaphore和mutex的区别?

记录几个我认为不错的答案,来自知乎-semaphore和mutex的区别?

作者:fleuria
链接:https://www.zhihu.com/question/47704079/answer/136200849
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Mutex 相比信号量增加了所有权的概念,一只锁住的 Mutex 只能由给它上锁的线程解开,只有系铃人才能解铃。Mutex 的功能也就因而限制在了构造临界区上。

一元信号量则可以由任一线程解开。这样多出来的一份语义,就是解决读者-写者问题的工具。比如某进程读取磁盘并进入睡眠,等待中断读取盘块结束之后来唤醒它。这就是可以祭出一元信号量的一个情景,而 Mutex 是解决不了的。『信号量』 这个词本身来自火车站的信号灯,其实本来就暗含着一层 『通知』 的含义。

『同步』这个词也可以拆开看,一侧是等待数据的『事件』或者『通知』,一侧是保护数据的 『临界区』。信号量可以满足这两个功能,但是可以注意到两个功能的应用场景还是蛮大的,有 do one thing and do it best 的空间。linux 内核曾将 semaphore 作为同步原语,后面代码变得较难维护,刷了一把 mutex 变简单了不少还变快了,需要『通知』 的场景则替换为了 completion variable。semaphore都变成二等公民了

Goodbye semaphores?

Difference between completion variables and semaphores

How are mutexes and semaphores different with respect to their implementation in a Linux kernel?

Some facts on mutex in Linux.
- only one task can hold the mutex at a time
- only the owner can unlock the mutex (unlike the semaphore)
- multiple unlocks are not permitted
- recursive locking is not permitted (since here count can be maximum 1 unlike the semaphore where for e.g count = 5)
- task may not exit with mutex held
- memory areas where held locks reside must not be free
- mutexes may not be used in hardware or software interrupt contexts such as tasklets and timers
这个回答提到的重要的一点:mutex和semaphore最大的差异是有ownership机制
 
 
作者:匿名用户
链接:https://www.zhihu.com/question/47704079/answer/216430116
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

A mutex
is essentially the same thing as a binary semaphore and sometimes uses
the same basic implementation. The differences between them are in how
they are used. While a binary semaphore may be used as a mutex, a mutex
is a more specific use-case, in that only the thread that locked the
mutex is supposed to unlock it. This constraint makes it possible to
implement some additional features in mutexes:

 

  1. Since only the thread that locked the mutex is supposed to unlock
    it, a mutex may store the id of thread that locked it and verify the
    same thread unlocks it.
  2. Mutexes may provide priority inversion
    safety. If the mutex knows who locked it and is supposed to unlock it,
    it is possible to promote the priority of that thread whenever a
    higher-priority task starts waiting on the mutex.
  3. Mutexes may also provide deletion safety, where the thread holding the mutex cannot be accidentally deleted.
  4. Alternately, if the thread holding the mutex is deleted (perhaps due
    to an unrecoverable error), the mutex can be automatically released.
  5. A mutex may be recursive: a thread is allowed to lock it multiple times without causing a deadlock.
这个回答提到重要的一点,mutex可以用来解决priority inversion(优先级倒置)
此外mutex可以recursive吗?为什么前面那个回答说不可以
 
 
 
作者:二律背反
链接:https://www.zhihu.com/question/47704079/answer/135859188
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

mutex,一句话:保护共享资源。
典型的例子就是买票:
票是共享资源,现在有两个线程同时过来买票。如果你不用mutex在线程里把票锁住,那么就可能出现“把同一张票卖给两个不同的人(线程)”的情况。
我想这个不需要多解释了。


一般人不明白semaphore和mutex的区别,根本原因是不知道semaphore的用途。
semaphore的用途,一句话:调度线程
有的人用semaphore也可以把上面例子中的票“保护"起来以防止共享资源冲突,必须承认这是可行的,但是semaphore不是让你用来做这个的;如果你要做这件事,请用mutex。

在网上、包括stackoverflow等著名论坛上,有一个流传很广的厕所例子:
mutex是一个厕所一把钥匙,谁抢上钥匙谁用厕所,谁没抢上谁就等着;semaphore是多个同样厕所多把同样的钥匙 ---- 只要你能拿到一把钥匙,你就可以随便找一个空着的厕所进去。
事实上,这个例子对初学者、特别是刚刚学过mutex的初学者来说非常糟糕 ----- 我第一次读到这个例子的第一反应是:semaphore是线程池???所以,请务必忘记这个例子
另外,有人也会说:mutex就是semaphore的value等于1的情况。
这句话不能说不对,但是对于初学者来说,请先把这句话视为错误;等你将来彻底融会贯通这部分知识了,你才能真正理解上面这句话到底是什么意思。总之请务必记住:mutex干的活儿和semaphore干的活儿不要混起来。


在这里,我模拟一个最典型的使用semaphore的场景:
a源自一个线程,b源自另一个线程,计算c = a + b也是一个线程。(即一共三个线程)

显然,第三个线程必须等第一、二个线程执行完毕它才能执行。
在这个时候,我们就需要调度线程了:让第一、二个线程执行完毕后,再执行第三个线程。
此时,就需要用semaphore了。
thread barrier
int a, b, c;
void geta()
{
    a = calculatea();
    semaphore_increase();
}

void getb()
{
    b = calculateb();
    semaphore_increase();
}


void getc()
{
    semaphore_decrease();
    semaphore_decrease();
    c = a + b;
}

t1 = thread_create(geta);
t2 = thread_create(getb);
t3 = thread_create(getc);
thread_join(t3);

// semaphore的机制我在这里就不讲了,百度一下你就知道。
// semaphore_increase对应sem_post
// semaphore_decrease对应sem_wait

这就是semaphore最典型的用法。

说白了,调度线程,就是:一些线程生产(increase)同时另一些线程消费(decrease),semaphore可以让生产和消费保持合乎逻辑的执行顺序。
而线程池是程序员根据具体的硬件水平和不同的设计需求、为了达到最佳的运行效果而避免反复新建和释放线程同时对同一时刻启动的线程数量的限制,这完全是两码事。
比如如果你要计算z = a + b +...+ x + y ...的结果,同时每个加数都是一个线程,那么计算z的线程和每个加数的线程之间的逻辑顺序是通过semaphore来调度的;而至于你运行该程序的时候到底要允许最多同时启动几个线程,则是用线程池来实现的。

semaphore和条件锁的区别:
条件锁,本质上还是锁,它的用途,还是围绕“共享资源”的。条件锁最典型的用途就是:防止不停地循环去判断一个共享资源是否满足某个条件。
比如还是买票的例子:
我们除了买票的线程外,现在再加一个线程:如果票数等于零,那么就要挂出“票已售完”的牌子。这种情况下如果没有条件锁,我们就不得不在“挂牌子”这个线程里不断地lock和unlock而在大多数情况下票数总是不等于零,这样的结果就是:占用了很多CPU资源但是大多数时候什么都没做。
另外,假如我们还有一个线程,是在票数等于零时向上级部门申请新的票。同理,问题和上面的一样。而如果有了条件锁,我们就可以避免这种问题,而且还可以一次性地通知所有被条件锁锁住的线程。
这里有个问题,是关于条件锁的:pthread_cond_wait 为什么需要传递 mutex 参数?
不清楚条件锁的朋友可以看一下。
总之请记住:条件锁,是为了避免绝大多数情况下都是lock ---> 判断条件 ----> unlock的这种很占资源但又不干什么事情的线程。它和semaphore的用途是不同的。


简而言之,锁是服务于共享资源的;而semaphore是服务于多个线程间的执行的逻辑顺序的。

这个回答主要讲mutex和semaphore的应用场景不同,semaphore用于线程调度,最典型的有读者-写着问题,mutex用于资源互斥保护
 
posted @ 2021-09-30 19:57  Rogn  阅读(214)  评论(0编辑  收藏  举报