c++ atomic库和atomic_flag库

  • atomic types是可以封装值的类型,保证不产生数据竞争,可用于多线程间内存访问的同步。

1.类classes

1.1 atomic

  • 保证多线程的访问不会导致数据竞争
    atmoic对象通过指定不同的memory orders可以保证其所在线程的其他non-atomic对象的访问同步。
template  struct atomic;
  • 1)构造函数
//default (1)   
          atomic() noexcept = default;

//initialization (2)    
constexpr atomic (T val) noexcept;

//copy [deleted] (3)    
          atomic (const atomic&) = delete;
// constructing atomics
#include        // std::cout
#include          // std::atomic, std::atomic_flag, ATOMIC_FLAG_INIT
#include          // std::thread, std::this_thread::yield
#include          // std::vector

std::atomic ready (false);
std::atomic_flag winner = ATOMIC_FLAG_INIT;

void count1m (int id) {
  while (!ready) { std::this_thread::yield(); }      // wait for the ready signal
  for (volatile int i=0; i<1000000; ++i) {}          // go!, count to 1 million
  if (!winner.test_and_set()) { std::cout << "thread #" << id << " won!\n"; }
};

int main ()
{
  std::vector threads;
  std::cout << "spawning 10 threads that count to 1 million...\n";
  for (int i=1; i<=10; ++i) threads.push_back(std::thread(count1m,i));
  ready = true;
  for (auto& th : threads) th.join();

  return 0;
}
  • 2)赋值运算
    该操作是原子的,使用顺序一致性(memory_order_seq_cst)。
set value (1)   
T operator= (T val) noexcept;
T operator= (T val) volatile noexcept;
copy [deleted] (2)  
atomic& operator= (const atomic&) = delete;
atomic& operator= (const atomic&) volatile = delete;
  • 3)is_lock_free
    检查对象是否没有加锁。

  • 4)store
    该操作是原子的,memory ordering由sync指定。

void store (T val, memory_order sync = memory_order_seq_cst) volatile noexcept;

void store (T val, memory_order sync = memory_order_seq_cst) noexcept;
  • 5)load
T load (memory_order sync = memory_order_seq_cst) const volatile noexcept;

T load (memory_order sync = memory_order_seq_cst) const noexcept;
  • 6)operator T
operator T() const volatile noexcept;
operator T() const noexcept;

//使用实例
std::atomic foo = 0;
std::atomic bar = 0;

bar = static_cast(foo);
  • 7)exchange
    将值替换为val并返回之前的值。
T exchange (T val, memory_order sync = memory_order_seq_cst) volatile noexcept;

T exchange (T val, memory_order sync = memory_order_seq_cst) noexcept;
// atomic::exchange example
#include        // std::cout
#include          // std::atomic
#include          // std::thread
#include          // std::vector

std::atomic ready (false);
std::atomic winner (false);

void count1m (int id) {
  while (!ready) {}                  // wait for the ready signal
  for (int i=0; i<1000000; ++i) {}   // go!, count to 1 million
  if (!winner.exchange(true)) { std::cout << "thread #" << id << " won!\n"; }
};

int main ()
{
  std::vector threads;
  std::cout << "spawning 10 threads that count to 1 million...\n";
  for (int i=1; i<=10; ++i) threads.push_back(std::thread(count1m,i));
  ready = true;
  for (auto& th : threads) th.join();

  return 0;
}
  • 8)compare_exchange_weak
    比较atomic对象封装的值和expected的值:
    a.如果为true,则将val的值存入atomic对象
    b.如果为false,则将atomic里面的值赋值给expected
    版本2根据比较结果指定了memory order,true选择success,false选择failure。
    weak版本可能会发生伪失败,即相等时也会返回false。这是可以接受的,因为并没有修改expected。用在循环中,在某些平台上可能显著提高性能。
    对于非循环算法,优先使用strong版本。
bool compare_exchange_weak (T& expected, T val,
           memory_order sync = memory_order_seq_cst) volatile noexcept;
bool compare_exchange_weak (T& expected, T val,
           memory_order sync = memory_order_seq_cst) noexcept;

bool compare_exchange_weak (T& expected, T val,
           memory_order success, memory_order failure) volatile noexcept;
bool compare_exchange_weak (T& expected, T val,
           memory_order success, memory_order failure) noexcept;
// atomic::compare_exchange_weak example:
#include        // std::cout
#include          // std::atomic
#include          // std::thread
#include          // std::vector

// a simple global linked list:
struct Node { int value; Node* next; };
std::atomic list_head (nullptr);

void append (int val) {     // append an element to the list
  Node* oldHead = list_head;
  Node* newNode = new Node {val,oldHead};

  // what follows is equivalent to: list_head = newNode, but in a thread-safe way:
  while (!list_head.compare_exchange_weak(oldHead,newNode))
    newNode->next = oldHead;
}

int main ()
{
  // spawn 10 threads to fill the linked list:
  std::vector threads;
  for (int i=0; i<10; ++i) threads.push_back(std::thread(append,i));
  for (auto& th : threads) th.join();

  // print contents:
  for (Node* it = list_head; it!=nullptr; it=it->next)
    std::cout << ' ' << it->value;
  std::cout << '\n';

  // cleanup:
  Node* it; while (it=list_head) {list_head=it->next; delete it;}

  return 0;
}
  • 9)compare_exchange_strong
    不允许伪失败
bool compare_exchange_strong (T& expected, T val,
           memory_order sync = memory_order_seq_cst) volatile noexcept;
bool compare_exchange_strong (T& expected, T val,
           memory_order sync = memory_order_seq_cst) noexcept;

bool compare_exchange_strong (T& expected, T val,
           memory_order success, memory_order failure) volatile noexcept;
bool compare_exchange_strong (T& expected, T val,
           memory_order success, memory_order failure) noexcept;
  • 10)特定基础类型支持的算术运算


    c++ atomic库和atomic_flag库_第1张图片


    fetch_add +=
    fetch_sub -=
    fetch_and &=
    fetch_or |=
    fetch_xor ^=
    operator++/--


//if T is integral (1)  
T fetch_add (T val, memory_order sync = memory_order_seq_cst) volatile noexcept;
T fetch_add (T val, memory_order sync = memory_order_seq_cst) noexcept;

//if T is pointer (2)   
T fetch_add (ptrdiff_t val, memory_order sync = memory_order_seq_cst) volatile noexcept;
T fetch_add (ptrdiff_t val, memory_order sync = memory_order_seq_cst) noexcept;
//pre-increment (1) 
T operator++() volatile noexcept;
T operator++() noexcept;

//post-increment (2)    
T operator++ (int) volatile noexcept;
T operator++ (int) noexcept;

1.2 atomic_flag

  • atomic flags是lock-free
struct atomic_flag;
  • 1)构造函数
    默认初始化的状态是不定的。除非初始化为宏ATOMIC_FLAT_INIT。此时保证为clear状态。
atomic_flag() noexcept = default;
atomic_flag (const atomic_flag&T) = delete;
  • 2)test_and_set
    set atomic_flag,并且返回调用该函数之前atomic_flag是否被set。
bool test_and_set (memory_order sync = memory_order_seq_cst) volatile noexcept;
bool test_and_set (memory_order sync = memory_order_seq_cst) noexcept;
// atomic_flag as a spinning lock
#include        // std::cout
#include          // std::atomic_flag
#include          // std::thread
#include          // std::vector
#include         // std::stringstream

std::atomic_flag lock_stream = ATOMIC_FLAG_INIT;
std::stringstream stream;

void append_number(int x) {
  while (lock_stream.test_and_set()) {}
  stream << "thread #" << x << '\n';
  lock_stream.clear();
}

int main ()
{
  std::vector threads;
  for (int i=1; i<=10; ++i) threads.push_back(std::thread(append_number,i));
  for (auto& th : threads) th.join();

  std::cout << stream.str();
  return 0;
}
  • 3)clear
    clear atomic_flag
void clear (memory_order sync = memory_order_seq_cst) volatile noexcept;
void clear (memory_order sync = memory_order_seq_cst) noexcept;

2.类型types

2.1 memory_order

  • 作为执行原子操作函数的参数,用于指定其他线程操作进行同步的方式。
  • 线程可能在atomic对象以外的内存位置进行操作。memory_order就是用来指定在线程间如何同步可见副作用。
  • memory_order_relaxed对线程见的内存访问不做任何保证;
    memory_order_consume,用于load操作,当所有对依赖释放操作的释放线程中内存访问发生后(对load线程由可见的副作用),该操作可以执行。
    memory_order_acquire,用于load操作。同上。
    memory_order_release,用于store操作。该操作在consume或者acquire之前发生。作为其他可能对load线程产生可见副作用的线程访问内存的同步点。
    memory_order_acq_rel,用于load/store操作。loads acquiring / stores releasing。
    memory_order_seq_cst,操作按照顺序一致的方式执行。当所有对其他线程产生可见副作用的内存访问已经发生后,这种类型的操作才安排执行。这是最严格的内存顺序,通过非原子内存访问保证线程交互之间最小的意外副作用。
typedef enum memory_order {
    memory_order_relaxed,   // relaxed
    memory_order_consume,   // consume
    memory_order_acquire,   // acquire
    memory_order_release,   // release
    memory_order_acq_rel,   // acquire/release
    memory_order_seq_cst    // sequentially consistent
} memory_order;

2.2 C-style atomic types

c++ atomic库和atomic_flag库_第2张图片

3.函数

3.1 函数

  • kill_dependency
    返回y的值,并且不保持任何依赖。
    使用memory_order_consume作为内存顺序的原子操作要求编译器检查 访问用于生成释放值的内存位置 所带来的依赖性。 同步这些携带的依赖关系可能导致某些硬件fence被设置并迫使编译器放弃涉及这些存储器位置的某些潜在优化。
template 
  T kill_dependency (T y) noexcept;
  • atomic_thread_fence
    建立多线程fence:对此函数的调用点将成为acquire或release同步点(或两者)。
extern "C" void atomic_thread_fence (memory_order sync) noexcept;
  • atomic_signal_fence同上
extern "C" void atomic_signal_fence (memory_order sync) noexcept;

3.2 Functions for atomic objects (C-style)

  • 同atomic对应的成员函数功能一样


    c++ atomic库和atomic_flag库_第3张图片

3.3 Functions for atomic flags (C-style)

  • 同atomic_flag成员函数功能相同


4.宏

4.1 宏函数

  • ATOMIC_VAR_INIT为了保持与C实现的兼容
  • ATOMIC_FLAG_INIT,初始化atomic flag为clear状态

4.2 宏常量

c++ atomic库和atomic_flag库_第4张图片

你可能感兴趣的:(c++ atomic库和atomic_flag库)