linux c/c++ 原子操作库 atomic atomic_flag 简介

目录

简介

1.类classes

1.1 atomic

1)构造函数

2)赋值运算

3)is_lock_free

4)store

5)load

6)operator T

7)exchange

8)compare_exchange_weak

9)compare_exchange_strong

10)特定基础类型支持的算术运算

1.2 atomic_flag

1)构造函数

2)test_and_set

3)clear

2.类型types

2.1 memory_order

2.2 C-style atomic types

3.函数

3.1 函数

3.2 Functions for atomic objects (C-style)

 3.3 Functions for atomic flags (C-style)

 4.宏

4.1 宏函数

4.2 宏常量


简介

Atomic types are types that encapsulate a value whose access is guaranteed to not cause data races and can be used to synchronize memory accesses among different threads.

原子类型是封装一个值的类型,这个值的访问被保证不会导致数据竞争,并且可以用于同步不同线程之间的内存访问。

This header declares two C++ classes, atomic and atomic_flag, that implement all the features of atomic types in self-contained classes. The header also declares an entire set of C-style types and functions compatible with the atomic support in C.

这个头声明了两个 c + + 类,atomic 和 atomic _ flag,它们在自包含的类中实现了原子类型的所有特性。标头还声明了一组完整的 c 样式类型和函数,它们与 c 语言中的原子支持兼容。

1.类classes

1.1 atomic

保证多线程的访问不会导致数据竞争
atmoic对象通过指定不同的memory orders可以保证其所在线程的其他non-atomic对象的访问同步。

template <class T> 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 <iostream>       // std::cout
#include <atomic>         // std::atomic, std::atomic_flag, ATOMIC_FLAG_INIT
#include <thread>         // std::thread, std::this_thread::yield
#include <vector>         // std::vector

std::atomic<bool> 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<std::thread> 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<int> foo = 0;
std::atomic<int> bar = 0;

bar = static_cast<int>(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 <iostream>       // std::cout
#include <atomic>         // std::atomic
#include <thread>         // std::thread
#include <vector>         // std::vector

std::atomic<bool> ready (false);
std::atomic<bool> 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<std::thread> 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 <iostream>       // std::cout
#include <atomic>         // std::atomic
#include <thread>         // std::thread
#include <vector>         // std::vector

// a simple global linked list:
struct Node { int value; Node* next; };
std::atomic<Node*> 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<std::thread> 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)特定基础类型支持的算术运算

 

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 <iostream>       // std::cout
#include <atomic>         // std::atomic_flag
#include <thread>         // std::thread
#include <vector>         // std::vector
#include <sstream>        // 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<std::thread> 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

3.函数

3.1 函数

kill_dependency
返回y的值,并且不保持任何依赖。
使用memory_order_consume作为内存顺序的原子操作要求编译器检查 访问用于生成释放值的内存位置 所带来的依赖性。 同步这些携带的依赖关系可能导致某些硬件fence被设置并迫使编译器放弃涉及这些存储器位置的某些潜在优化。

template <class T>
  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对应的成员函数功能一样

 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 宏常量

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值