任何解释每一个的实时场景将不胜感激。除了pthreads中的这些之外,还有其他方法可以处理同步吗?互斥锁与递归互斥锁(任何实时场景)有何不同?
2 回答
互斥锁可用于保护共享资源(变量、文件、外围设备)免受可能使其处于不一致状态的修改。
信号量可用于管理相同共享资源的有限池(其中一个重要的例子是IPC 队列)。线程可以从池中获取资源,将资源放入池中,或等待资源可用。请注意,除了信号量之外,您可能仍需要使用互斥锁(以保护池数据结构本身)。
读写锁可用于保护可以读取或写入(修改)的共享资源。所有阅读器线程都可以同时访问它。写线程需要独占访问。
条件变量可以与互斥体一起使用,以发出事件信号。
维基百科可以用来阅读大部分内容。
boost::interprocess
这在文档中得到了非常明确的回答
什么是互斥锁?
Mutex 代表互斥,它是进程之间最基本的同步形式。互斥锁保证只有一个线程可以锁定给定的互斥锁。如果代码段被互斥锁和解锁包围,则可以保证每次只有一个线程执行该段代码。当该线程解锁互斥锁时,其他线程可以进入该代码区域:
//互斥体之前已经构造好了
lock_the_mutex();
//这段代码一次只能由一个线程执行。
unlock_the_mutex(); 互斥体也可以是递归的或非递归的:
递归互斥锁可以被同一个线程多次锁定。要完全解锁互斥锁,线程必须在锁定互斥锁的同时解锁互斥锁。非递归互斥锁不能被同一个线程多次锁定。如果一个互斥锁被一个线程锁定了两次,结果是未定义的,它可能会抛出一个错误或者线程可能永远被阻塞。提升进程间文档
和
什么是信号量?
信号量是基于内部计数的进程之间的同步机制,它提供两个基本操作:
等待:测试信号量计数的值,如果值小于或等于 0,则等待。否则,递减信号量计数。Post:增加信号量计数。如果任何进程被阻塞,则其中一个进程被唤醒。如果初始信号量计数初始化为 1,Wait 操作相当于互斥锁,Post 相当于互斥锁解锁。这种类型的信号量称为二进制信号量。
尽管信号量可以像互斥体一样使用,但它们有一个独特的特性:与互斥体不同,Post 操作不需要由执行 Wait 操作的同一线程/进程执行。 boost::进程间文档
boost interprocess 没有明确地具有称为读写器锁的东西,但是它确实使用shared_locks
, 和 aupgrade_lock
来实现它们upgrade_to_unique lock
什么是可共享和可升级互斥锁?
可共享和可升级互斥锁是特殊的互斥锁类型,它提供比普通互斥锁更多的锁定可能性。有时,我们可以区分读取数据和修改数据。如果只是一些线程需要修改数据,并且使用纯互斥锁来保护数据不被并发访问,那么并发性是非常有限的:两个只读取数据的线程将被序列化而不是并发执行。
如果我们允许并发访问只读取数据的线程,但我们避免读取和修改线程之间或修改线程之间的并发访问,我们可以提高性能。在数据读取比数据修改更常见并且同步数据读取代码需要一些时间执行的应用程序中尤其如此。使用可共享的互斥锁,我们可以获得 2 种锁类型:
排他锁:类似于普通的互斥锁。如果一个线程获得了排他锁,则在释放排他锁之前,其他线程都不能获得任何锁(排他或其他)。如果任何其他线程拥有除独占之外的任何锁,则试图获取独占锁的线程将阻塞。此锁将由将修改数据的线程获取。共享锁:如果一个线程获取了共享锁,其他线程就无法获取独占锁。如果任何线程获得了独占锁,则试图获得共享锁的线程将阻塞。这种锁定由只需要读取数据的线程执行。使用可升级互斥锁,我们可以获得以前的锁和新的可升级锁:
可升级锁:获取可升级锁类似于获取特权共享锁。如果一个线程获得了一个可升级的锁,其他线程就可以获得一个共享的锁。如果任何线程获得了排他锁或可升级锁,则试图获得可升级锁的线程将阻塞。一个获得了可升级锁的线程,当其他获得共享锁的线程释放它时,保证能够原子地获得排他锁。这用于可能需要修改数据但通常只需要读取数据的线程。该线程获取升级锁,其他线程获取共享锁。如果可升级线程读取数据并且必须对其进行修改,则可以提升线程以获取排他锁:当所有可共享线程都释放了可共享锁时,可升级锁自动升级为独占锁。新提升的线程可以修改数据,并且可以确保在进行转换时没有其他线程修改过它。只有 1 个线程可以获得可升级(特权读者)锁。 提升进程间文档
C++ 本身还没有reader-writer locks
(使用共享互斥锁),但@Howard Hinnet 确实尝试将它们放在那里,如果你看这里,他还提供了代码
C++ 没有信号量,据我所知,互斥锁只在新的 C++11 标准中,这导致了为什么大部分都是关于boost::interprocess