pthreads互斥与信号量


73

pthread库提供的信号量和互斥量有什么区别?


11
pthreads不提供信号量,也可以在非线程程序中使用。
短暂

5
可以在非线程代码中使用任何同步构造:P
Hassan Syed 2010年

4
好吧,我要强调的区别是在pthread之前使用了信号量。您可以将a放置sem_t在共享内存中,并使用它在进程之间同步操作。另一方面,即使您不创建多个线程,也必须进行编译和链接-pthread才能使用pthread_mutex_*。(某些平台不强制执行此操作,但这是标准。)
短暂的

2
@ephemient,实际上man sem_init在Linux中说:Link with -pthread.所以我想Linux并不遵循POSIX。
2014年

Answers:


77

信号量具有同步计数器,互斥量仅是二进制的(真/假)。

信号量通常用作回答正在使用资源的多少元素的确定机制-例如,表示n个工作线程的对象可能使用信号量来计算有多少个工作线程可用。

事实是,您可以通过由互斥锁同步的INT来表示信号量。



157
一个显着的区别(因为我以前见过人们犯过这个错误):信号量可以由任何线程以任何顺序获得和腾空(只要计数永远不为负),但是互斥锁只能由该线程解锁锁定了它。尝试解锁被另一个线程锁定的互斥锁是未定义的行为。
短暂

5
@ephemient,会作出一个伟大的回答,非常有见地
马特·乔伊纳

9
@ephemient:由于您指定的原因,答案中的最后一个断言为假:您无法通过由互斥锁同步的INT表示信号量,因为如果持有互斥锁,则无法从另一个互斥量递增/递减int线程,则必须等待锁定线程释放互斥量。基石的区别是互斥体是所有者,而信号量是不所有者。并通过强加的同步将该所有权传送给INT。因此,您将获得一些混合的,拥有的信号量,该信号量介于未拥有的信号量和拥有的互斥量之间。
user1284631 2013年

19
我认为这个答案仍然错过了信号量和互斥量之间的一个非常关键的区别。这就是用法。信号量是其核心信号机制。它们可以由任何线程递增和递减的事实仅仅是此结果。信号量用于向其他控制流发出与同步相关的信号(例如,完全/空缓冲区)。另一方面,互斥锁始终用于保护对共享对象的多次访问。那是一个很大的差异,人们似乎总是以某种方式会错过它,或者我永远都不明白他们想说什么。:P
Fingolfin 2013年

18

我将谈论Mutex与Binary-Semaphore。您显然使用互斥锁来防止一个线程中的数据同时被另一个线程访问。

(假设您刚刚调用过lock(),并且正在访问数据。这意味着,您不希望任何其他线程(或同一线程代码的另一个实例)访问由锁锁定的相同数据。相同的互斥锁。也就是说,如果在不同的线程实例上执行的是同一线程代码,则会命中该锁,然后lock()应该会阻塞控制流。

这适用于使用不同线程代码的线程,该线程代码也正在访问相同的数据,并且也被相同的互斥锁锁定。

在这种情况下,您仍处于访问数据的过程中,并且可能需要花费15秒钟的时间才能达到互斥锁解锁(这样,在互斥锁中被阻塞的另一个线程将解除阻塞并允许控件访问数据)。

您是否曾经允许另一个线程仅解锁相同的互斥锁,然后又允许互斥锁中已在等待(阻塞)的线程解除阻塞并访问数据?(希望您明白我在这里说的话。)

根据公认的通用定义,

  • 使用“互斥体”不会发生这种情况。没有其他线程可以解锁您线程中的锁
  • 使用“二进制信号量”会发生这种情况。任何其他线程都可以解锁您线程中的锁

因此,如果您非常在意使用二进制信号量而不是互斥量,那么您应该非常谨慎地“确定”锁定和解锁范围,我的意思是,碰到每个锁的每个控制流都应该碰到一个解锁调用不应有任何“首次解锁”,而应始终是“首次锁定”。


我喜欢范围界定部分。它指的是二进制信号量和互斥量不同的实现部分。
舒瓦

6

互斥锁用于避免多个线程之间的竞争状态。

信号量用作跨多个进程使用的同步元素。

互斥锁不能用二进制信号量代替,因为,一个进程等待信号量,而另一个进程释放信号量。在互斥锁的情况下,获取和释放都由相同的对象处理。


1
(-1)不正确的概括:其中之一是,互斥量可以在进程之间共享-例如:msdn.microsoft.com/en-us/library/ms682411(VS.85).aspx。如果您的系统未命名为互斥锁,则只需映射一些共享内存并创建自己的共享内存即可。
哈桑·赛义德

1
将其标记为“无用”是不公平的。我已经为M $工作了很多。告诉别人使用共享内存很容易。在M $上,所有内核对象都被命名和共享。Mutex是一个内核对象。pthread互斥锁是M $中的CRITICAL_SECTION。无法在进程之间共享CRITICAL_SECTION!
hackworks,2010年

@hackworks-可以使用“ _POSIX_THREAD_PROCESS_SHARED”标志初始化pthread_mutex,该标志使其可以在进程间环境中工作:linux.die.net/man/3/pthread_mutexattr_init
killdaclick 2013年

6

厕所的例子

互斥体:

是上厕所的钥匙。一个人可以当时拥有钥匙-上厕所。完成后,该人将密钥提供(释放)给队列中的下一个人。

“ Mutexe通常用于序列化不能由多个线程同时执行的可重入代码段的访问。互斥对象仅允许一个线程进入受控段,从而迫使其他试图访问该段的线程等到第一个线程从该部分退出。”

(互斥量实际上是值为1的信号量。)

信号:

是免费的相同马桶钥匙的数量。例如,假设我们有四个具有相同锁和钥匙的卫生间。信号量计数(键的计数)在开始时设置为4(所有四个洗手间都是免费的),然后计数值随着人们的进来而递减。没有剩余的可用键,信号量为0。一个人离开洗手间,信号量增加到1(一个自由键),并交给队列中的下一个人。

“信号量将共享资源的同时用户数限制为最大数量。线程可以请求访问该资源(减少信号量),并可以发出信号,表明他们已完成使用该资源(增加信号量)。”

资源


4

semaphore和之间的mutex区别是机制模式之间的区别。它们的目的(意图)和工作方式(行为)不同。

mutexbarrierpipeline并行编程模式Mutex用于(旨在)保护critical section和确保mutual exclusionBarrier使代理(线程/进程)保持彼此等待。

的特征(行为)之一mutex模式是,只有允许的代理(进程或线程)可以进入关键部分,而只有该代理可以自愿退出。

在某些情况下,一次mutex允许一个代理。在某些情况下,它允许多个代理(多个读者)而不允许某些其他代理(作家)。

semaphore是一种机制,可用于(意图)来实现不同的图案。通常,它是(行为)一个标志(可能受到互斥保护)。(一个有趣的事实是甚mutex至可以使用模式来实现信号量)。

在流行文化中,semaphores内核提供了一些机制,并且mutexes,用户空间库提供。

请注意,关于semaphores和存在误解mutexes。它说semaphores用于synchronization。并且mutexesownership。这是由于流行的OS书籍。但事实是所有互斥量,信号量和障碍都用于同步。互斥的目的不是,ownership而是mutual exclusion。这种误解引起了受欢迎的面试问题的提出,mutexes并要求两者之间的区别binary-semaphores

概要,

意图
  • 互斥,互斥
  • 信号量,实现并行设计模式
行为
  • 互斥体,仅允许的代理进入关键部分,并且只有其可以退出
  • 信号量,如果标志显示“ go”,请输入,否则请等到有人更改标志

从设计角度看,mutex更像state-pattern是状态选择的算法可以更改状态的地方。这binary-semaphore更像strategy-pattern外部算法可以更改状态并最终选择要运行的算法/策略的地方。



1

信号量更多地用作标志,为此您实际上不需要带RTOS / OS。信号量可能会被其他线程意外或故意更改(例如由于编码错误)。当线程使用互斥锁时,它拥有资源。在资源释放之前,没有其他线程可以访问它。


0

互斥体就像S与= 1的sempaphore。

您可以使用信号量控制并发访问的数量,但使用互斥锁一次只能访问一个进程。

请参见下面这两个的实现:(所有函数都是原子的)

信号:

互斥体:


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.