std :: atomic如何实现

我正在研究C ++ 11中mutexatomic之间的区别。

据我了解,mutex是一种锁定机制,它是基于OS /内核实现的。例如,Linux提供了一种机制,futex。借助futex,我们可以实现mutexsemaphore。此外,我知道futex是由低级原子操作实现的,例如CompareAndSetCompareAndSwap

对于std::atomic,我知道它是基于C ++ 11引入的内存模型实现的。但是,我不知道如何在底层实现内存模型。如果它也由CompareAndSet之类的原子操作实现,那么std::atomicmutex有什么区别?

总之,如果std::atomic::is_lock_free给我一个false,那么,我要说std::atomicmutex相同。但是,如果它给我一个true,它是如何在低级实现的?

xjdyjk2007 回答:std :: atomic如何实现

  

std::atomic和互斥锁之间有什么区别

互斥锁是一种并发构造,独立于任何用户数据,提供lockunlock方法,可让您保护(强制相互排斥)代码的区域 。您可以在该区域放任何东西。

std::atomic<T>类型T 的单个实例上的适配器,允许基于每个操作对该对象进行原子访问。

互斥锁从某种意义上讲是更普遍的,std::atomic的一种可能的实现是使用互斥锁保护对基础对象的所有访问。

std::atomic之所以存在,主要是因为 other 常见的实现方式:使用原子指令 2 直接执行操作而无需互斥。这是std::atomic<T>::is_lock_free()返回true时使用的实现。这通常比互斥锁方法更有效,但仅适用于足够小以通过原子指令“一次性完成”操作的对象。


2 在某些情况下,编译器能够使用 plain 指令(而不是与特殊并发相关的指令),例如正常的加载和存储(如果它们提供了所需的保证)在相关平台上。例如,在x86上,compilers implement的所有负载,甚至seq_cst都具有普通负载,并使用普通存储实现发布存储。 seq_cst存储区通过特殊指令实现,但是-mfence上的尾随clang和gcc上的lock xchg。还要注意,加载和存储之间的不对称性是编译器的选择:它们本来可以对seq_cst加载进行特殊处理,但是因为在大多数情况下,加载通常要比存储慢得多。

,

如果原子操作为lock_free,则它们的实现方式可能与实现互斥锁的组件相同。毕竟,要锁定一个互斥锁,您确实需要某种原子操作来确保只有一个线程锁定该互斥锁。

不同之处在于,无锁定的原子操作没有“锁定”状态。让我们比较一下两种可能的方法来对变量进行原子递增:

首先,互斥方式。我们锁定一个互斥锁,我们以递增方式写入变量,然后解锁互斥锁。如果线程在读增量写入期间被中断,则其他尝试执行此相同操作的线程将阻止尝试锁定互斥锁。 (请参阅Where is the lock for a std::atomic?,以了解在某些实际实现中该方法如何工作,对于太大而无法锁死的对象。)

第二,原子方式。 CPU仅在一条读-增量-写指令的持续时间内“锁定”包含我们要修改的变量的高速缓存行。 (这意味着CPU会延迟响应使MESI请求无效或共享高速缓存行,从而保持排他访问,因此其他CPU都无法查看它。MESI高速缓存一致性始终要求高速缓存行具有排他所有权,然后内核才能对其进行修改,因此这是便宜(如果我们已经拥有该线路)。我们不可能在指令中被打断。另一个尝试访问此变量的线程,在最坏的情况下,必须等待缓存一致性硬件找出谁可以修改内存位置。

那么我们如何锁定互斥锁?可能我们执行原子比较和交换。因此,轻原子操作是组装重互斥操作的基元。

当然,这都是特定于平台的。但这就是您可能会使用的典型现代平台。

本文链接:https://www.f2er.com/2977942.html

大家都在问