简体   繁体   English

原子变量是否无锁?

[英]Are atomic variables lock-free?

When we talk about atomic variables, such as C++11's atomic<> , is it lock free? 当我们谈论原子变量,比如C ++ 11的atomic<> ,它是否可以自由锁定? Or is lock-freeness something different? 或者锁定是不同的东西? If I manage a queue with atomic variables, will it be slower than a lock-free queue? 如果我使用原子变量管理队列,它会比无锁队列慢吗?

The standard does not specify if atomic objects are lock-free. 该标准未指定原子对象是否无锁。 On a platform that doesn't provide lock-free atomic operations for a type T, atomic<T> objects may be implemented using a mutex, which wouldn't be lock-free. 在不为类型T提供无锁原子操作的平台上,可以使用互斥锁来实现atomic<T>对象,该互斥锁不是无锁的。 In that case, any containers using these objects in their implementation would not be lock-free either. 在这种情况下,在其实现中使用这些对象的任何容器也不会是无锁的。

The standard does provide a way to check if an atomic<T> variable is lock-free: you can use var.is_lock_free() or atomic_is_lock_free(&var) . 该标准确实提供了一种检查atomic<T>变量是否无锁的方法:您可以使用var.is_lock_free()atomic_is_lock_free(&var) These functions are guaranteed to always return the same value for the same type T on a given program execution. 在给定的程序执行中,这些函数保证始终为相同类型T返回相同的值。 For basic types such as int , There are also macros provided (eg ATOMIC_INT_LOCK_FREE ) which specify if lock-free atomic access to that type is available. 对于诸如int类的基本类型,还提供了宏(例如ATOMIC_INT_LOCK_FREE ),它指定对该类型的无锁原子访问是否可用。

Lock-free usually applies to data structures shared between multiple threads, where the synchronisation mechanism is not mutual exclusion; 无锁通常适用于多线程之间共享的数据结构,其中同步机制不是互斥的; the intention is that all threads should keep making some kind of progress instead of sleeping on a mutex. 目的是所有线程都应该继续取得某种进展,而不是睡在互斥锁上。

atomic<T> variables don't use locks (at least where T is natively atomic on your platform), but they're not lock-free in the sense above. atomic<T>变量不使用锁(至少在你的平台上T本身是原子的),但在上面的意义上它们不是无锁的。 You might use them in the implementation of a lock-free container, but they're not sufficient on their own. 您可以在无锁容器的实现中使用它们,但它们本身并不足够。

Eg, atomic<queue<T>> wouldn't suddenly make a normal std::queue into a lock-free data structure. 例如, atomic<queue<T>>不会突然使普通的std::queue进入无锁数据结构。 You could however implement a genuinely lock-free atomic_queue<T> whose members were atomic . 但是,您可以实现一个真正无锁的atomic_queue<T>其成员是atomic

Note that even if atomic<int> is natively atomic and not emulated with a lock on your platform, that does not make it lock-free in any interesting way. 请注意,即使atomic<int>本身是原子的,并且未在您的平台上使用锁定进行模拟,也不会以任何有趣的方式使其无锁定 Plain int is already lock-free in this sense: the atomic<> wrapper gets you explicit control of memory ordering, and access to hardware synchronisation primitives. 从这个意义上说,Plain int 已经是无锁的: atomic<>包装器可以显式控制内存排序,并可以访问硬件同步原语。

Marketting and cool factor aside, it does not make a twopenny toss of a difference whether the magic C++ syntactic (brown) sugar ends up implementing a direct bus lock or a mutex (which might rely on bus locks but, as a commentator noted, takes advantage of OS internals to do it in a more efficient way), or nothing at all if you are unlucky enough to run on a single-procesor architecture. 除了市场营销和冷却因素外,无论是神奇的C ++语法(棕色)糖是否最终实现直接总线锁定或互斥锁(可能依赖于总线锁定,但正如评论员指出的那样),它并没有产生差别。操作系统内部的优势是以更有效的方式完成它,或者如果你不幸运行在单处理器架构上,那就什么也不做。

Mutex are semantically lock free already. 互斥锁在语义上已经锁定。 They implement all you might dream of in terms of scheduler-niceness, namely priority inversion handling and reentrancy. 它们在调度程序 - 良好性方面实现了您可能梦寐以求的一切,即优先级反转处理和重入。 You cannot deadlock on a mutex (well actually you might if you tried very hard, but as far as guarding a variable is concerned, you won't), and using a mutex will not have any more noticeable side effect on the other processes or the operating system than a bus-locked variable. 不能在互斥锁上陷入僵局(实际上,如果你非常努力,你可能会这么做,但就保护变量而言,你不会),并且使用互斥锁对其他进程不会产生任何明显的副作用或操作系统比总线锁定变量。

The only difference is that a programmer might (by design or by mistake) hold a mutex for an unreasonable amount of time, while an equally incompetent programmer might poll on a "Wait-free" variable and achieve the same silly results, with a catastrophic bus slowdown that will put a lot more stress on the system as a whole than a faulty mutex use (OK, my previous allusion to a BSOD was just a juvenile provokation, though I still suspect some drivers might not react very kindly to heavy bus contention). 唯一的区别是程序员可能(通过设计或错误地)持有一个互联网一段不合理的时间,而一个同样无能的程序员可能会在“无等待”变量上进行轮询并获得相同的愚蠢结果,带来灾难性的总线减速会给整个系统带来更大的压力,而不是使用有缺陷的互斥锁(好吧,我之前对BSOD的暗示只是一个少年的挑战,但我仍然怀疑一些司机可能不会对重型公交车的争用做出非常友善的反应)。 Anyway, this problem is soon solved when the mutex calls are wrapped around a linear access to a reasonably small amount of memory. 无论如何,当互斥锁调用绕过对相当少量内存的线性访问时,这个问题很快就会解决。

"Lock free" is selling dreams to wanabee hardboiled programmers. “免费锁定”正在向wanabee强硬的程序员推销梦想。 I find it quite amusing that a mechanism that indeeds relies on locking the multiprocessor bus might be called that. 我觉得很有趣的是,可以调用依赖于锁定多处理器总线的机制。

What a "Lock free" variable access does is pester the hardware by neutering the bus cache system, forbidding bus access scheduling, and generally disabling all the mechanisms that allow your average multiprocessor bus to do a decent job. “无锁”变量访问的作用是通过中断总线缓存系统,禁止总线访问调度来破坏硬件,并且通常禁用允许平均多处理器总线执行体面工作的所有机制。
Each time you're accessing a "Lock free" magic variable, you are pelting a handful of sand into the bus controller's cogwheels. 每次你访问“无锁定”魔法变量时,你都会将一把沙子扔进总线控制器的齿轮中。

Like any concurrent access mechanism, bus-locked variables (sorry, I meant "Lock free variables") are costly and have potential negative side effects that are extremely difficult to predict or even diagnose . 与任何并发访问机制一样,总线锁定变量(对不起,我的意思是“锁定自由变量”)成本高,并且具有潜在的负面影响, 极难预测甚至诊断

As long as you're using these new shiny toys as you would mutexes, ie very sparsely and only for a few good reasons (and no, acting the super cool Mr wait-free is not one of them), it's fine. 只要你使用这些新的闪亮玩具就像你的互斥体一样,即非常稀疏而且仅仅是出于一些好的理由(而且,没有,代表超级酷的无等待先生不是其中之一),这很好。

But if you start sprinkling bus locks all over the place, or (God forbids!) polling bus-locked variables as a cheap and easy replacement for proper synchronization objects (what the super cool Mr wait-free might call "brewing your own homemade spinlocks in 3 easy steps"), you will only manage to turn whatever cutting edge hardware your code runs on into a circa 1995 Pentium I emulator. 但是,如果你开始在整个地方洒上公共汽车锁,或者(上帝禁止!) 轮询公共汽车锁定变量作为适当同步对象的便宜和容易的替代品(超级酷先生等待的可能称之为“酿造你自己的自制螺旋锁通过3个简单的步骤“),您将只能将代码运行的任何尖端硬件转换为大约1995年的Pentium I仿真器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM