目录
3.2 Functions for atomic objects (C-style)
3.3 Functions for atomic flags (C-style)
简介
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,memory_order sync = memory_order_seq_cst) noexcept;
bool compare_exchange_weak (T& expected,memory_order success,memory_order failure) volatile noexcept;
bool compare_exchange_weak (T& expected,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,memory_order sync = memory_order_seq_cst) volatile noexcept;
bool compare_exchange_strong (T& expected,memory_order sync = memory_order_seq_cst) noexcept;
bool compare_exchange_strong (T& expected,memory_order failure) volatile noexcept;
bool compare_exchange_strong (T& expected,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)
3.3 Functions for atomic flags (C-style)
4.宏
4.1 宏函数
ATOMIC_VAR_INIT为了保持与C实现的兼容
ATOMIC_FLAG_INIT,初始化atomic flag为clear状态
4.2 宏常量
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。