Kar*_*uru 106 linux multithreading synchronization mutex semaphore
我们何时应该使用互斥锁?什么时候应该使用信号量?
小智 85
这是我记得何时使用什么 -
信号量: 当你(线程)想要睡觉时使用信号量,直到某个其他线程告诉你醒来.信号量'down'发生在一个线程(生产者)中,而信号量'up'(相同的信号量)发生在另一个线程(消费者)中,例如:在生产者 - 消费者问题中,生产者想睡觉直到至少一个缓冲槽为空 - 仅消费者线程可以判断缓冲槽何时为空.
互斥锁: 当您(线程)想要执行不应由任何其他线程同时执行的代码时,请使用互斥锁.Mutex'down'在一个线程中发生,互斥'up' 必须在稍后的同一个线程中发生.例如:如果要从全局链接列表中删除节点,则在删除节点时,不希望其他线程使用指针.当您获取互斥锁并且正在忙于删除节点时,如果另一个线程尝试获取相同的互斥锁,则它将被释放,直到您释放互斥锁.
Spinlock: 当你真的想使用互斥锁但是你的线程不允许睡眠时使用自旋锁.例如:OS内核中的中断处理程序绝对不能休眠.如果是,系统将冻结/崩溃.如果需要从中断处理程序向全局共享链接列表插入节点,请获取自旋锁 - 插入节点 - 释放自旋锁.
pax*_*blo 56
互斥锁是一个互斥对象,类似于信号量,但它一次只允许一个锁定器,其所有权限制可能比信号量更严格.
它可以被认为等同于正常的计数信号量(计数为1),并且要求它只能由锁定它的同一个线程释放(a).
另一方面,信号量具有任意计数,并且可以同时被多个储物柜锁定.并且它可能没有要求它被声明它的同一个线程释放(但是,如果没有,你必须仔细跟踪当前对它负责的人,就像分配的内存一样).
因此,如果您有多个资源实例(例如三个磁带驱动器),您可以使用一个计数为3的信号量.请注意,这并不能告诉您这些磁带驱动器中的哪一个,只是您拥有一定数量.
此外,对于信号量,单个锁定器可以锁定资源的多个实例,例如磁带到磁带的副本.如果您有一个资源(比如一个您不想破坏的内存位置),则互斥锁更合适.
等效操作是:
Counting semaphore Mutual exclusion semaphore
-------------------------- --------------------------
Claim/decrease (P) Lock
Release/increase (V) Unlock
Run Code Online (Sandbox Code Playgroud)
旁白:如果你曾经想过用于声称和发布信号量的奇怪信件,那是因为发明者是荷兰人.探测器te verlagen意味着尝试减少,而verhogen意味着增加.
(a) ......或者它可以被认为是与信号量完全不同的东西,考虑到它们几乎总是不同的用途,它们可能更安全.
Pee*_*ger 45
理解互斥锁不是计数1的信号量非常重要!
这就是二进制信号量(它们实际上是计数器1的信号量)之类的东西.
Mutex和Binary-Semaphore之间的区别是所有权原则:
互斥锁由任务获取,因此也必须由同一任务释放.这使得修复二进制信号量(Accidential release,recursive deadlock和priority inversion)的几个问题成为可能.
警告:我写道"让它成为可能",这些问题是否以及如何解决取决于操作系统的实现.
因为必须通过相同的任务释放互斥锁,所以对于任务的同步来说不是很好.但如果与条件变量结合使用,您将获得用于构建各种ipc原语的非常强大的构建块.
所以我的建议是:如果你有干净实现的互斥锁和条件变量(比如POSIX pthreads),请使用这些.
仅在信号量与您尝试解决的问题完全匹配时才使用信号量,不要尝试构建其他基元(例如,信号量中的rw-locks,使用互斥锁和条件变量)
有很多误解互斥和信号量.到目前为止,我发现的最佳解释是在这篇3部分文章中:
Mutex vs. Semaphores - 第1部分:信号量
Mutex vs. Semaphores - 第2部分:互斥体
Mutex vs. Semaphores - 第3部分(最后部分):相互排斥问题
Pat*_*ter 13
虽然@opaxdiablo答案是完全正确的,但我想指出两者的使用场景是完全不同的.互斥锁用于保护代码部分不会同时运行,信号量用于一个线程以指示另一个线程运行.
/* Task 1 */
pthread_mutex_lock(mutex_thing);
// Safely use shared resource
pthread_mutex_unlock(mutex_thing);
/* Task 2 */
pthread_mutex_lock(mutex_thing);
// Safely use shared resource
pthread_mutex_lock(mutex_thing);
Run Code Online (Sandbox Code Playgroud)
信号量场景不同:
/* Task 1 - Producer */
sema_post(&sem); // Send the signal
/* Task 2 - Consumer */
sema_wait(&sem); // Wait for signal
Run Code Online (Sandbox Code Playgroud)
有关详细说明,请访问http://www.netrino.com/node/202
请参阅"厕所示例" - http://pheatt.emporia.edu/courses/2010/cs557f10/hand07/Mutex%20vs_%20Semaphore.htm:
互斥:
是厕所的关键.一个人可以拥有钥匙 - 占用厕所 - 当时.完成后,该人员将(释放)密钥提供给队列中的下一个人.
正式说:"互斥锁通常用于序列化对一部分重入代码的访问,这些代码不能由多个线程同时执行.互斥对象只允许一个线程进入受控部分,强制其他线程尝试访问该部分要等到第一个线程退出该部分." 参考:Symbian开发人员库
(互斥体实际上是一个值为1的信号量.)
信号:
是免费相同的厕所钥匙的数量.例如,我们说有四个带有相同锁和钥匙的马桶.信号量计数 - 键数 - 在开始时设置为4(所有四个厕所都是免费的),然后计数值随着人们的进入而减少.如果所有厕所都已满,即.没有剩余的自由键,信号量计数为0.现在,当eq.一个人离开厕所,信号量增加到1(一个自由键),并给予队列中的下一个人.
正式地说:"信号量将共享资源的同时用户数量限制为最大数量.线程可以请求访问资源(递减信号量),并且可以发信号通知他们已经完成了使用资源(递增信号量). " 参考:Symbian开发人员库
尽量不听声音,但不能帮助自己.
你的问题应该是互斥和信号量之间的区别是什么?而更准确的问题应该是,"互斥和信号量之间的关系是什么?"
(我本来会添加这个问题,但我百分百肯定一些过分热心的主持人会将其作为重复关闭而不理解差异和关系之间的区别.)
在对象术语中,我们可以观察到:
观察.1信号量包含互斥量
观察.2互斥量不是信号量,信号量不是互斥量.
有一些信号量就好像它们是互斥量一样,称为二进制信号量,但它们并不是互斥量.
有一种称为信号的特殊成分(posix使用condition_variable作为该名称),需要用互斥量制作信号量.将其视为通知源.如果两个或多个线程订阅了相同的通知源,则可以将消息发送到ONE或ALL,以进行唤醒.
可能有一个或多个与信号量相关联的计数器,这些计数器由互斥锁保护.对于信号量最简单的场景,有一个计数器可以是0或1.
这就像季风雨一样涌入困境.
具有可以是0或1的计数器的信号量不是互斥量.
互斥有两种状态(0,1)和一种所有权(任务).信号量有一个互斥锁,一些计数器和一个条件变量.
现在,运用你的想象力,计数器的使用和何时发出信号的每种组合都可以成为一种信号量.
值为0或1的单个计数器,当值变为1时发出信号然后解锁其中一个等待信号的人==二进制信号量
单个计数器,其值为0到N,当值小于N时发出信号,并在值为N = =计数信号量时锁定/等待
值为0到N的单个计数器,当值变为N时发出信号,当值小于N =阻隔信号量时锁定/等待(如果他们不调用它,那么它们应该.)
现在问你的问题,何时使用什么.(或者更正确的问题版本.3何时使用互斥锁以及何时使用二进制信号量,因为没有与非二进制信号量进行比较.)当您想要自定义行为时使用互斥量,二进制不提供信号量,例如自旋锁或快速锁或递归锁.您通常可以使用属性自定义互斥锁,但自定义信号量只不过是编写新的信号量.2.你想要轻量级或更快的原语
当你想要的东西完全由它提供时,使用信号量.
如果你不明白你的二进制信号量的实现提供了什么,那么恕我直言,使用互斥量.
最后读了一本书,而不仅仅依靠SO.
我认为问题应该是互斥量和二进制信号量之间的区别.
Mutex =它是一种所有权锁定机制,只有获得锁定的线程才能释放锁定.
二进制信号量=它更像是一个信号机制,任何其他更高优先级的线程,如果想要信号并采取锁定.
Mutex 是为了保护共享资源。
信号量用于调度线程。
Mutex:
想象一下,有一些门票要卖。我们可以模拟多人同时购票的情况:每个人都是一个线程来买票。显然我们需要使用互斥锁来保护票证,因为它是共享资源。
信号量:
想象一下我们需要做如下计算:
c = a + b;
Run Code Online (Sandbox Code Playgroud)
此外,我们需要一个函数geta()来计算a,函数getb()计算b和功能getc()做计算c = a + b。
显然,我们不能做c = a + b除非geta()和getb()已经完成。
如果这三个函数是三个线程,我们需要分派这三个线程。
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);
Run Code Online (Sandbox Code Playgroud)
随着信号的帮助下,上面的代码可以确保t3不会做其工作,直到t1和t2做他们的工作。
总之,信号量是让线程按照逻辑顺序执行,而互斥量是为了保护共享资源。
所以即使有人总是说互斥是一个特殊的信号量,初始值为1,它们也不是一回事。你也可以这样说,但请注意它们用于不同的情况。即使你能做到,也不要用另一个替换。