C ++ 11原子类和操作 - 我是对的

时间:2014-02-28 08:52:46

标签: c++ multithreading c++11

我在以下假设中是对的:

  • 我不需要使用我自己的同步对象显式同步来自任何平台上不同线程的std::atomic<T>对象的访问权
  • std::atomic<T>操作可以是无锁的,也可以是非锁定的,具体取决于平台
  • std::atomic_boolstd::atomic<bool>(以及其他类似的)实际上是相同的事情
  • std::atomic_flag是唯一一个通过标准
  • 保证与平台无关的无锁操作的类

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

1 个答案:

答案 0 :(得分:6)

让我们逐一介绍。


  • 我不需要使用我自己的同步对象显式同步来自任何平台上不同线程的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_boolstd::atomic<bool>(以及其他类似的)实际上是相同的事情

是的,为方便起见,这些只是typedef。完整列表见标准表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有一篇关于如何使用内存栅栏进行无锁编程的精彩文章。