互斥锁、信号量和读写锁有什么区别?

9

如果有实时场景举例解释每个问题将会很有帮助。 除了pthread中的这些方法,是否还有其他处理同步的方式? 互斥锁与递归锁有什么不同(任何实时场景)?


"实时"是指实时应用程序吗?(比如游戏) - Borgleader
实际上阅读一下Boost Interprocess文档,它们有时是相同的。 - Eiyrioü von Kauyf
@Borgleader,游戏不是实时应用程序。至少不是硬实时。请确保不要混淆高性能和实时性。[维基百科](https://en.wikipedia.org/wiki/Real-time_computing#Criteria_for_real-time_computing) - Shahbaz
@user2601350,如果您能展现一些努力就好了。您已经搜索和找到了什么呢?互联网上有许多关于同步机制的文章。 - Shahbaz
2
@Shahbaz 卖弄学问的争论是没有意义的。我只是想对他所指的应用程序类型进行澄清。 - Borgleader
@Shahbaz 笑话很好。OP没有明确说明实时是什么意思。我在询问这个,因为操作系统和游戏都属于“实时应用程序”的大类别。虽然它可能指的是后者,但这是SO,人们经常错误地使用术语。 - Borgleader
2个回答

9

互斥锁可用于保护共享资源(变量、文件、外围设备)免受可能导致其处于不一致状态的修改。

信号量可以用于管理有限数量的相同共享资源(重要案例之一是IPC队列)。线程可以从池中获取资源,将资源放回池中,或等待直到有资源可用。请注意,您可能仍需要使用互斥锁以及信号量(以保护池数据结构本身)。

读写锁可用于保护可读或可写(修改)的共享资源。所有读取线程可以同时访问它。写入线程需要独占访问。

条件变量可与互斥锁一起使用,以发出事件信号。

维基百科 可用于了解大部分相关信息。


根据您的解释,读写锁和互斥锁有什么不同?我感到困惑。 - user3104760
3
读写锁类似于互斥锁,但有两种访问类型:读和写。而互斥锁所有的访问都是相同的。读写锁不允许同时进行写访问以及其他任何形式的访问,但可以同时进行多个读访问。互斥锁则不允许同时进行任何形式的访问。 - n. m.

2

这在boost::interprocess文档中有明确的解释。

什么是互斥锁?

互斥锁是进程间最基本的同步形式,用于互斥访问共享资源。互斥锁保证只有一个线程可以锁定给定的互斥锁。如果一个代码区域被互斥锁锁定和解锁,那么保证只有一个线程执行该代码区域。当该线程解锁互斥锁时,其他线程可以进入该代码区域:

//互斥锁已经被构造

lock_the_mutex();

//这段代码将只由一个线程执行

unlock_the_mutex(); 互斥锁也可以是递归或非递归的:

递归互斥锁可以被同一线程多次锁定。为了完全解锁互斥锁,线程必须解锁相同次数的互斥锁。非递归互斥锁不能被同一线程多次锁定。如果一个线程两次锁定一个互斥锁,则结果是未定义的,可能会抛出错误,也可能会永久阻塞线程。

boost interprocess docs

以及

什么是信号量?

信号量是一种基于内部计数的进程间同步机制,提供两个基本操作:

等待:测试信号量计数的值,如果该值小于或等于0,则等待。否则,减少信号量计数。发布:增加信号量计数。如果有任何进程被阻塞,则唤醒其中一个进程。如果初始信号量计数初始化为1,则等待操作相当于互斥锁定,发布操作相当于互斥解锁。这种类型的信号量称为二进制信号量。

虽然信号量可以像互斥锁一样使用,但它们具有独特的特点:与互斥锁不同,发布操作不必由执行等待操作的同一线程/进程执行。

boost::interprocess文档

boost interprocess没有明确的读写锁,但是使用shared_locksupgrade_lockupgrade_to_unique lock实现了它们。

可共享和可升级的互斥锁是一种特殊的互斥锁类型,提供比普通互斥锁更多的锁定可能性。有时候,我们可以区分数据的读取和修改。如果只有一些线程需要修改数据,并且使用普通互斥锁来保护数据免受并发访问,那么并发性就非常有限:只读取数据的两个线程将被串行化而不是同时执行。如果我们允许线程并发访问只读取数据,但避免线程在读取和修改或修改之间的并发访问,就可以提高性能。这在数据读取比数据修改更常见且同步数据读取代码需要一些时间执行的应用程序中尤为真实。使用可共享的互斥锁,我们可以获得2种锁类型:
独占锁:类似于普通互斥锁。如果一个线程获取了独占锁,则没有其他线程可以获取任何锁(独占或其他),直到独占锁被释放。如果任何其他线程有除独占之外的任何锁,则试图获取独占锁的线程将被阻塞。这个锁将被将要修改数据的线程获取。
共享锁:如果一个线程获取了共享锁,则其他线程无法获取独占锁。如果任何线程已经获得了独占锁以外的任何锁,则试图获取共享锁的线程将被阻塞。这个锁是由只需要读取数据的线程执行的。
使用可升级的互斥锁,我们可以获得之前的锁加上一个新的可升级锁:
可升级锁:获取可升级锁类似于获取特权共享锁。如果一个线程获取了可升级锁,则其他线程可以获取共享锁。如果任何线程已经获取了独占或可升级锁,则试图获取可升级锁的线程将被阻塞。已经获取了可升级锁的线程,保证可以在其他获取了共享锁的线程释放该锁时原子地获取独占锁。这用于可能需要修改数据但通常只需要读取数据的线程。该线程获取可升级锁,其他线程可以获取共享锁。如果可升级线程读取数据并且必须修改它,则该线程可以提升为获取独占锁:当所有共享线程释放共享锁时,可升级锁会自动升级为独占锁。新提升的线程可以修改数据,并确保在过渡期间没有其他线程修改它。只有1个线程可以获取可升级(特权读者)锁。 boost interprocess文档

C++本身还没有支持读写锁(使用共享互斥体),但@Howard Hinnet曾经试图将其加入其中,如果您在这里查看,他还提供了代码。

C ++没有信号量,而且据我所知,互斥锁仅在新的C ++11标准中存在,这就是为什么大多数内容都涉及到boost :: interprocess的原因。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接