【问题标题】:C++11 atomic classes and operations -- am I rightC++11 原子类和操作——我说得对吗
【发布时间】:2014-03-18 02:25:48
【问题描述】:

我的以下假设是否正确:

  • 我不需要将任何平台上不同线程对std::atomic<T> 对象的访问与我自己的同步对象显式同步
  • std::atomic<T> 操作可以是无锁或非无锁的,取决于平台
  • std::atomic_boolstd::atomic<bool>(以及其他类似的类型)实际上是相同的东西
  • std::atomic_flag 是唯一按标准保证独立于平台的无锁操作的类

我在哪里可以找到有关std::memory_order 的有用信息以及如何正确使用它?

【问题讨论】:

  • 如果std::memory_order 有比cppreference.com 更好的总结,我还没有找到。我会从那开始。

标签: c++ multithreading c++11


【解决方案1】:

我们来一一介绍。


  • 我不需要将任何平台上不同线程对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&lt;T&gt; 操作可以是无锁或非无锁的,取决于平台

正确。对于所有整数类型,您可以检查一些宏来告诉您给定的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_boolstd::atomic&lt;bool&gt;(以及其他类似的类型)实际上是相同的东西

是的,为了您的方便,这些只是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 有一篇关于如何使用内存栅栏进行无锁编程的精彩文章。

【讨论】:

  • [Boost.Atomic][0]s 关于 memory_order 的文章更容易理解恕我直言。 [0]:boost.org/doc/libs/1_55_0/doc/html/atomic/…
  • 这是我在 StackOverflow 上读到的最彻底、最清晰的答案之一。
  • 我猜对于 memory_order 的东西来说,行动中的并发是好的书,但我不记得确切......
猜你喜欢
  • 2016-06-10
  • 2015-01-10
  • 2017-11-25
  • 1970-01-01
  • 2013-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-09
相关资源
最近更新 更多