什么时候应该使用互斥体,什么时候应该使用信号量
我们什么时候应该使用互斥量,什么时候应该使用信号量?
下面是我记得什么时候使用什么 –
信号量(Semaphore):当(线程)想要睡觉之前使用一个信号量,直到其他线程告诉你醒来。 信号量'down'发生在一个线程(生产者)和信号量'up'(对于相同的信号量)发生在另一个线程(消费者)中,例如:在生产者 – 消费者问题中,生产者想睡觉,直到至less一个缓冲器槽为空消费者线程可以知道什么时候缓冲槽是空的。
互斥体:当(线程)想要执行不应该被任何其他线程同时执行的代码时,使用互斥体。 互斥'down'发生在一个线程中,互斥'up' 必然发生在同一个线程中。 例如:如果从全局链表中删除一个节点,那么在删除该节点时,不希望另一个线程在指针上乱搞。 当你获得一个互斥体并且正在忙于删除一个节点时,如果另一个线程试图获得相同的互斥体,它将会进入睡眠状态直到你释放互斥体。
旋转locking:当你真的想要使用一个互斥锁时,使用一个自旋锁,但是你的线程不允许进入睡眠状态。 例如:操作系统内核中的中断处理程序一定不能睡眠。 如果这样做,系统将冻结/崩溃。 如果您需要从中断处理程序中将节点插入到全局共享链表中,请获取一个自旋锁 – 插入节点释放螺旋锁。
互斥对象是一个互斥对象, 类似于信号量,但一次只允许一个锁柜,其所有权限制可能比信号量更严格。
它可以被认为等同于一个正常的计数信号量(计数为1),并且只能由locking它的同一个线程来释放(a) 。
另一方面,信号量具有任意数量,并且可以被许多储物柜同时locking。 而且它可能没有要求它被同一个线程声明的要求(但是,如果不是,你必须仔细地跟踪谁目前负责它,就像分配的内存)。
所以,如果你有一个资源的实例(比如三个磁带驱动器),你可以使用一个计数为3的信号量。注意,这并不告诉你这些磁带驱动器是哪一个,只是你有一定数量。
此外,对于信号量,单个locking器可以locking资源的多个实例,例如磁带到磁带复制。 如果你有一个资源(比如说你不想破坏的内存位置),那么互斥量就更适合了。
等同的操作是:
Counting semaphore Mutual exclusion semaphore -------------------------- -------------------------- Claim/decrease (P) Lock Release/increase (V) Unlock
另外:如果你曾经想知道用于声明和释放信号量的奇怪信件,那是因为发明者是荷兰人。 Probeer te verlagen意味着尝试减less,而verhogen意味着增加。
(a) …或者它可以被认为是完全不同于信号量的东西,由于它们几乎总是不同的用途,所以它可能更安全。
了解一个互斥量不是一个数量为1的信号量是非常重要的!
这就是二进制信号量的原因(实际上信号量是1)。
互斥和二元信号的区别是所有权的原则:
互斥体是由任务获得的,因此也必须由同一个任务释放。 这样就可以解决二进制信号(事件释放,recursion死锁和优先级倒置)的几个问题。
警告:我写了“使之成为可能”,如果以及如何解决这些问题取决于操作系统的实施。
因为互斥量必须由同一个任务释放,所以对于任务的同步并不是很好。 但是,如果与条件variables相结合,您将获得用于构build各种ipc基元的非常强大的构build块。
所以我的build议是:如果你得到干净的实施互斥和条件variables(如与POSIX pthreads)使用这些。
只有在符合你正在尝试解决的问题的时候才使用信号量,不要试图build立其他的原语(例如,rw-lock在信号灯之外,使用互斥锁和条件variables)
有很多的误解互斥和信号量。 我发现迄今为止最好的解释是在这篇3部分的文章中:
互斥量与信号量 – 第1部分:信号量
互斥量与信号量 – 第2部分:互斥量
互斥与信号 – 第3部分(最后部分):互斥问题
虽然@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);
信号量情况是不同的:
/* Task 1 - Producer */ sema_post(&sem); // Send the signal /* Task 2 - Consumer */ sema_wait(&sem); // Wait for signal
请参阅“厕所示例” – http://pheatt.emporia.edu/courses/2010/cs557f10/hand07/Mutex%20vs_%20Semaphore.htm :
互斥:
是厕所的关键。 一个人可以拥有钥匙 – 占用厕所 – 当时。 完成后,该人员将(释放)队列中下一个人的钥匙。
正式地说:“互斥锁通常用来串行访问一段不能同时被多个线程执行的重入代码,一个互斥对象只允许一个线程进入一个受控节,强制其他线程尝试访问该部分要等到第一个线程退出该部分。“ 参考:Symbian开发人员库
(互斥量实际上是一个值为1的信号量。)
信号:
是免费的相同的马桶钥匙的数字。 比如说,我们有四个带有相同的锁和钥匙的洗手间。 信号计数 – 密钥计数 – 在开始时设置为4(所有四个厕所都是免费的),然后计数值随着人们进入而递减。如果所有的厕所都满了, 没有空闲密钥,信号计数为0.现在,当等式 一个人离开厕所,信号量增加到1(一个自由键),并给予队列中的下一个人。
正式地说:“一个信号量限制共享资源的并发用户数达到最大值,线程可以请求访问资源(递减信号量),并可以表示他们已经完成使用资源(增加信号量)。 “ 参考:Symbian开发人员库
试着不要发出z </s>声,但不能帮助自己。
你的问题应该是互斥信号和信号量有什么区别? 更确切地说,问题应该是“互斥体和信号量之间的关系是什么?
(我会加上这个问题,但我百分之百肯定某些过分热心的主持人将它作为重复closures,而不理解差异和关系之间的差异。)
在对象术语中,我们可以观察到:
观察1。信号量含有互斥量
观察.2互斥量不是信号量,信号量不是互斥量。
有一些信号量,就好像它们是互斥体一样,称为二进制信号量,但它们却不是互斥体。
有一种称为Signaling的特殊成分(posix使用condition_variable来表示这个名字),它是使用一个信号量从互斥量中获得的。 把它看作通知源。 如果两个或多个线程订阅了相同的通知源,则可以将消息发送给“1”或“全部”以唤醒。
可能有一个或多个与信号量相关的计数器,这些计数器由互斥锁保护。 信号量最简单的情况是,有一个计数器可以是0或1。
这是像季风雨一样混乱的地方。
计数器可以是0或1的信号量不是互斥量。
互斥体有两个状态(0,1)和一个所有权(任务)。 信号量有一个互斥量,一些计数器和一个条件variables。
现在,用你的想象力,每一个计数器的使用和什么时候发出信号的组合都可以成为一种信号量。
-
值为0或1的单个计数器,当值变为1时发出信号然后解锁等待信号的人之一==二进制信号量
-
单个计数器的值为0到N,当值变为小于N时发信号,当值为N时locking/等待计数信号量
-
单个计数器的值为0到N,并在值变为N时发信号,当值小于N时locking/等待信号量(如果他们不调用它,那么他们应该)。
现在到你的问题,什么时候用什么。 (或者是比较正确的问题版本3.什么时候使用互斥体,什么时候使用二进制信号量,因为没有和非二进制信号量的比较。)1.当你想要一个自定义的行为,而不是二进制提供的信号量,例如自旋锁或快锁或recursion锁。 你通常可以定制具有属性的互斥体,但是定制信号量只不过是写新的信号量而已。 2.你想轻量级或更快的原始
使用信号量,当你想要的是完全由它提供的。
如果你不明白什么是由你的二进制信号的实现提供,那么恕我直言,使用互斥。
最后读一本书,而不是依靠SO。
我认为这个问题应该是互斥信号和二进制信号的区别。
互斥锁=它是一个所有权锁机制,只有获得锁的线程才能释放锁。
二进制信号量=它是更多的信号机制,任何其他更高优先级的线程,如果想要信号和locking。
互斥是保护共享资源。
信号量是派遣线程。
互斥:
想象一下,有一些门票卖。 我们可以模拟很多人同时购票的情况:每个人都是买票的线索。 显然我们需要使用互斥体来保护票据,因为它是共享资源。
信号:
想象一下,我们需要做一个计算如下:
c = a + b;
此外,我们需要一个函数geta()
来计算a
,一个函数getb()
来计算b
和一个函数getc()
去计算c = a + b
。
显然,除非geta()
和getb()
已经完成,否则我们不能做c = a + b
。
如果三个函数是三个线程,我们需要调度三个线程。
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);
在信号量的帮助下,上面的代码可以确保t3
不会完成它的工作,直到t1
和t2
完成它们的工作。
总之,信号量是使线程作为逻辑顺序执行,而互斥量则是保护共享资源。
所以即使有些人总是说互斥量是一个初始值为1的特殊信号量,它们也不是一回事。你也可以这样说,但请注意,它们在不同的情况下使用。 即使你能做到这一点,也不要一个人replace。
正如已经指出的那样,一个计数为1的信号与“二进制”信号相同,它和互斥一样。
我所看到的信号量大于所使用的信号量的主要原因是生产者/消费者情况,在这种情况下,你有一个固定大小的队列。
那么你有两个信号量。 第一个信号量最初设置为队列中的项目数,第二个信号量设置为0.生产者对第一个信号量执行P操作,将其添加到队列中。 并在第二个V操作。 消费者对第二个信号量执行P操作,从队列中移除,然后对第一个信号执行V操作。
通过这种方式,只要生产者填满了队列,生产者就被阻塞,并且只要队列为空,消费者就被阻塞。
互斥量是信号量的特例。 信号量允许多个线程进入关键部分。 在创build信号量时,您可以定义关键部分中允许线程的情况。 当然你的代码必须能够处理对这个关键部分的多次访问。