我们来一一介绍。
- 我不需要将任何平台上不同线程对
std::atomic<T> 对象的访问与我自己的同步对象显式同步
是的,atomic 对象在其所有访问器方法上完全同步。
只有在构造过程中才会发生访问原子类型的数据竞争,但它涉及构造一个原子对象A,并使用memory_order_relaxed通过原子指针将其地址传递给另一个线程,以有意解决std::atomic 的顺序一致性,然后从第二个线程访问A。所以,不要那样做? :)
说到构造,可以通过三种方式来初始化你的原子类型:
// Method 1: constructor
std::atomic<int> my_int(5);
// Method 2: atomic_init
std::atomic<int> my_int; // must be default constructed
std::atomic_init(&my_int, 5); // only allowed once
// Method 3: ATOMIC_VAR_INIT
// may be implemented using locks even if std::atomic<int> is lock-free
std::atomic<int> my_int = ATOMIC_VAR_INIT(5);
使用后两种方法中的任何一种,都适用相同的数据竞争可能性。
-
std::atomic<T> 操作可以是无锁或非无锁的,取决于平台
正确。对于所有整数类型,您可以检查一些宏来告诉您给定的atomic 特化是否、有时或总是无锁。对于这三种情况,宏的值分别为 0、1 或 2。完整的宏列表取自标准的 §29.4,其中unspecified 是它们的“0、1 或 2”的替代:
#define ATOMIC_BOOL_LOCK_FREE unspecified
#define ATOMIC_CHAR_LOCK_FREE unspecified
#define ATOMIC_CHAR16_T_LOCK_FREE unspecified
#define ATOMIC_CHAR32_T_LOCK_FREE unspecified
#define ATOMIC_WCHAR_T_LOCK_FREE unspecified
#define ATOMIC_SHORT_LOCK_FREE unspecified
#define ATOMIC_INT_LOCK_FREE unspecified
#define ATOMIC_LONG_LOCK_FREE unspecified
#define ATOMIC_LLONG_LOCK_FREE unspecified
#define ATOMIC_POINTER_LOCK_FREE unspecified
请注意,这些定义适用于相应类型的无符号和有符号变体。
如果#define 为1,则必须在运行时检查。这是按如下方式完成的:
std::atomic<int> my_int;
if (my_int.is_lock_free()) {
// do lock-free stuff
}
if (std::atomic_is_lock_free(&my_int)) {
// also do lock-free stuff
}
-
std::atomic_bool 和 std::atomic<bool>(以及其他类似的类型)实际上是相同的东西
是的,为了您的方便,这些只是typedefs。完整列表见标准表 194:
Named type | Integral argument type
----------------+-----------------------
atomic_char | char
atomic_schar | signed char
atomic_uchar | unsigned char
atomic_short | short
atomic_ushort | unsigned short
atomic_int | int
atomic_uint | unsigned int
atomic_long | long
atomic_ulong | unsigned long
atomic_llong | long long
atomic_ullong | unsigned long long
atomic_char16_t | char16_t
atomic_char32_t | char32_t
atomic_wchar_t | wchar_t
-
std::atomic_flag 是唯一一个按照标准保证独立于平台的无锁操作的类
正确,由标准中的 §29.7/2 保证。
请注意,atomic_flag 的初始化状态无法保证,除非您使用如下宏对其进行初始化:
std::atomic_flag guard = ATOMIC_FLAG_INIT; // guaranteed to be initialized cleared
其他原子类型也有类似的宏,
该标准未指定 atomic_flag 是否会遇到其他原子类型在构造期间可能遇到的相同数据竞争。
- 另外我在哪里可以找到有关
std::memory_order 的有用信息以及如何正确使用它?
正如@WhozCraig 所建议的,cppreference.com 有最好的参考。
正如@erenon 所建议的,Boost.Atomic 有一篇关于如何使用内存栅栏进行无锁编程的精彩文章。