原子变量是无锁的吗?

49
当我们谈论原子变量时,比如C++11的atomic<>,它是无锁的吗?还是无锁性是另一回事?如果我使用原子变量管理队列,它会比无锁队列慢吗?

https://dev59.com/fnNA5IYBdhLWcg3wgeOk - user195488
这个问题在这里也有回答:http://www.open-std.org/JTC1/sc22/wg21/docs/papers/2007/n2427.html#DiscussOperations 看起来它们是无锁的。 - user195488
2个回答

46
标准并未规定原子对象是否为无锁。在一个不提供类型T的无锁原子操作的平台上,atomic<T>对象可能会使用互斥锁来实现,这将不是无锁的。在这种情况下,任何使用这些对象的容器都不是无锁的。
标准确实提供了一种检查atomic<T>变量是否为无锁的方法:您可以使用var.is_lock_free()atomic_is_lock_free(&var)。这些函数保证在给定程序执行期间始终为相同类型的T返回相同的值。对于基本类型,如int,还提供了宏(例如ATOMIC_INT_LOCK_FREE),用于指定是否可用无锁原子访问该类型。

2
有趣的是,是否存在不提供任何无锁本地原子操作的平台,还是你只是意味着 atomic<T> 对于所有大小的 T 都可能不是本地原子的?我无法想象一个没有真正本地原子操作的平台如何首先实现互斥量... - Useless
3
可能你只有一个字节的原子操作在嵌入式平台上。因此,像 std::atomic<char> 这样的东西是无锁的。但是,如果 32 位整数通过进行 4 个字节操作来模拟,则这不是原子的。所以大多数情况下 std::atomic<int> 不会是无锁的。然而,你可以使用字节原子操作来创建互斥量(例如自旋锁)。 - KillianDS
@Useless:我的意思是,并非所有对象大小都支持无锁操作 - 我已经进行了编辑以澄清。我想理论上平台可以提供本地的锁定/解锁操作而不需要无锁原子操作,但我不知道有这样的平台。 - interjay
4
有些平台只有原子“交换”指令。您可以将其用于互斥锁和std::atomic_flag(必须是无锁的),但不能用于一般的原子操作(因为它不能进行简单的加载)。 - Anthony Williams
互斥锁在mutex::lock中如何实现而不使用至少一个原子操作? - muaz

16

无锁通常应用于多个线程共享的数据结构,其中同步机制不是互斥的;意图是所有线程都应该保持某种形式的进展,而不是在互斥量上睡眠。

atomic<T>变量不使用锁(至少在您的平台上T本地原子时),但它们在上述意义上不是无锁的。您可能会在无锁容器的实现中使用它们,但它们本身并不足够。

例如,atomic<queue<T>>不会突然将普通的std::queue变成无锁数据结构。不过您可以实现一个真正无锁的atomic_queue<T>,其成员为atomic

请注意,即使atomic<int>在您的平台上本地原子且没有使用锁进行仿真,这也不会以任何有趣的方式使其成为无锁。在此意义上,纯int已经是无锁的: atomic<>包装器可为您提供显式的内存顺序控制和访问硬件同步原语。


也许我将“无锁”和“非阻塞”混淆了,当谈论原语本身而不是使用它们的算法时,这肯定是模糊的。 - Useless
1
在x86架构中,普通的int在只有一个写入者的情况下是线程安全的,例如,如果读取者对其视图的实时性要求不高,则可以完全线程安全地使用普通的int来处理某些应用程序逻辑。 - Useless
我认为最后一条评论需要稍作说明。读取和写入操作保证是原子性的,并且读取操作总是适当有序的,但是写入操作可能会无序发生(尽管是原子性的)。如果int的值在逻辑上不意味着其他操作已经完成,那么是安全的。否则,您需要使用atomic<>来提供写入栅栏以确保因果关系。 - Tim Seguine
1
@Tim,关于“写入可能无序”的问题 - 不,x86的顺序保证了同一线程内的存储是有序的,并在多个线程上维护类似TSO的内存排序规则。但这与此无关 - 有序和原子加载和存储仍需要锁定,因为操作的原子性不能保证任何类型的交互原子性(即 - inc [x]可能具有原子加载和原子存储,但在这两者之间内存可能会发生变化)。 - Leeor
@Leeor 我想我需要稍微解释一下我的意思。在x86上,字大小的加载和存储始终是原子性的。在x86上,读操作是原子性的“获取/释放”操作。在x86上,写操作是原子性的,但不是“释放”操作,除非它们是“锁定”的,在这种情况下它们是“获取/释放”的。这足以保证因果关系。如果您看一下我的评论,我没有对跨操作的原子性做出任何声明。我只声称可以以无锁的方式保证因果关系。这足以正确地编写一些并行算法,而无需使用锁或竞争。 - Tim Seguine
显示剩余6条评论

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