C++11中头文件atomic的使用
原子庫為細粒度的原子操作提供組件,允許無鎖并發編程。涉及同一對象的每個原子操作,相對于任何其他原子操作是不可分的。原子對象不具有數據競爭(data race)。原子類型對象的主要特點就是從不同線程訪問不會導致數據競爭。因此從不同線程訪問某個原子對象是良性(well-defined)行為,而通常對于非原子類型而言,并發訪問某個對象(如果不做任何同步操作)會導致未定義(undifined)行為發生。
atomic是C++標準程序庫中的一個頭文件,定義了C++11標準中的一些表示線程、并發控制時原子操作的類與方法等。此頭文件主要聲明了兩大類原子對象:std::atomic和std::atomic_flag,另外還聲明了一套C風格的原子類型和與C兼容的原子操作的函數。在多線程并發執行時,原子操作是線程不會被打斷的執行片段。一些程序設計更為注重性能和效率,需要開發lock-free的算法和數據結構,這就需要更為底層的原子操作與原子類型。原子類型對象的主要特點就是從不同線程并發訪問是良性(well-defined)行為,不會導致競爭危害。與之相反,不做適當控制就并發訪問非原子對象則會導致未定義(undifined)行為。
atomic_flag類:是一種簡單的原子布爾類型,只支持兩種操作:test_and_set(flag=true)和clear(flag=false)。跟std::atomic的其它所有特化類不同,它是鎖無關的。結合std::atomic_flag::test_and_set()和std::atomic_flag::clear(),std::atomic_flag對象可以當作一個簡單的自旋鎖(spin lock)使用。atomic_flag只有默認構造函數,禁用拷貝構造函數,移動構造函數實際上也禁用。如果在初始化時沒有明確使用宏ATOMIC_FLAG_INIT初始化,那么新創建的std::atomic_flag對象的狀態是未指定的(unspecified),既沒有被set也沒有被clear;如果使用該宏初始化,該std::atomic_flag對象在創建時處于clear狀態。
(1)、test_and_set:返回該std::atomic_flag對象當前狀態,檢查flag是否被設置,若被設置直接返回true,若沒有設置則設置flag為true后再返回false。該函數是原子的。
(2)、clear:清除std::atomic_flag對象的標志位,即設置atomic_flag的值為false。
std::atomic類模板:std::atomic比std::atomic_flag功能更加完善。C++11標準庫std::atomic提供了針對bool類型、整形(integral)和指針類型的特化實現。每個std::atomic模板的實例化和完全特化定義一個原子類型。若一個線程寫入原子對象,同時另一個線程從它讀取,則行為良好定義。而且,對原子對象的訪問可以按std::memory_order所指定建立線程間同步,并排序非原子的內存訪問。std::atomic可以以任何可平凡復制(Trivially Copyable)的類型T實例化。std::atomic既不可復制亦不可移動。
除了std::atomic和std::atomic_flag外,<atomic>還包括了基于std::atomic_flag類的C風格API和基于std::atomic類模板的C風格API。
與原子對象初始化相關的兩個宏:
(1)、ATOMIC_VAR_INIT(val):初始化std::atomic對象。This macro expands to a token sequence suitable to initialize an atomic object (of static storage duration) with a value of val. This macro exists for compatibility with C implementations, in which it is used as a constructor-like function for(default-constructed) atomic objects; In C++, this initialization may be performed directly by the initialization constructor.
(2)、ATOMIC_FLAG_INIT:初始化std::atomic_flag對象。This macro is defined in such a way that it can be used to initialize an object of type atomic_flag to the clear state.
std::atomic:Objects of atomic types contain a value of a particular type (T). The main characteristic of atomic objects is that access to this contained value from different threads cannot cause data races (i.e., doing that is well-defined behavior, with accesses properly sequenced). Generally, for all other objects, the possibility of causing a data race for accessing the same object concurrently qualifies the operation as undefined behavior. Additionally, atomic objects have the ability to synchronize access to other non-atomic objects in their threads by specifying different memory orders.
std::atomic_flag:Atomic flags are boolean atomic objects that support two operations:test-and-set and clear.
下面是從其他文章中copy的<atomic>測試代碼,詳細內容介紹可以參考對應的reference:
?
#include "atomic.hpp"
#include <iostream>
#include <atomic>
#include <vector>
#include <thread>
#include <sstream>namespace atomic {
/
// reference: http://www.cplusplus.com/reference/atomic/atomic/atomic/
std::atomic<bool> ready(false);
// atomic_flag::atomic_flag: Constructs an atomic_flag object
// The atomic_flag is in an unspecified state on construction (either set or clear),
// unless it is explicitly initialized to ATOMIC_FLAG_INIT.
std::atomic_flag winner = ATOMIC_FLAG_INIT;void count1m(int id)
{while (!ready) { std::this_thread::yield(); } // wait for the ready signalfor (volatile int i = 0; i < 1000000; ++i) {} // go!, count to 1 millionif (!winner.test_and_set()) { std::cout << "thread #" << id << " won!\n"; }
};int test_atomic_atomic()
{// atomic::atomic: Constructs an atomic objectstd::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;
}/
// reference: http://www.cplusplus.com/reference/atomic/atomic/compare_exchange_weak/
// 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 listNode* 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 test_atomic_compare_exchange_weak()
{// atomic::compare_exchange_weak: Compares the contents of the atomic object's contained value with expected:// -if true, it replaces the contained value with val(like store).// - if false, it replaces expected with the contained value// 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;
}///
// reference: http://www.cplusplus.com/reference/atomic/atomic/exchange/
std::atomic<bool> winner_(false);void count1m_(int id)
{while (!ready) {} // wait for the ready signalfor (int i = 0; i<1000000; ++i) {} // go!, count to 1 millionif (!winner_.exchange(true)) { std::cout << "thread #" << id << " won!\n"; }
};int test_atomic_exchange()
{// atomic::exchange: Replaces the contained value by val and returns the value it had immediately beforestd::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;
}/
// reference: http://www.cplusplus.com/reference/atomic/atomic/load/
std::atomic<int> foo(0);void set_foo(int x)
{foo.store(x, std::memory_order_relaxed); // set value atomically
}void print_foo()
{int x;do {x = foo.load(std::memory_order_relaxed); // get value atomically} while (x == 0);std::cout << "foo: " << x << '\n';
}int test_atomic_load()
{// atomic::load: Returns the contained value.// The operation is atomic and follows the memory ordering specified by sync.std::thread first(print_foo);std::thread second(set_foo, 10);first.join();second.join();return 0;
}// reference: http://www.cplusplus.com/reference/atomic/atomic/operator=/
std::atomic<int> foo_ = 0;void set_foo_(int x)
{foo_ = x;
}void print_foo_()
{while (foo_ == 0) { // wait while foo_=0std::this_thread::yield();}std::cout << "foo_: " << foo_ << '\n';
}int test_atomic_operator()
{// atomic::operator=: Replaces the stored value by val.// This operation is atomic and uses sequential consistency (memory_order_seq_cst).// To modify the value with a different memory orderingstd::thread first(print_foo_);std::thread second(set_foo_, 10);first.join();second.join();return 0;
}///
// reference: http://www.cplusplus.com/reference/atomic/atomic/store/
int test_atomic_store()
{// atomic::store: Replaces the contained value with val.// The operation is atomic and follows the memory ordering specified by sync.std::thread first(print_foo);std::thread second(set_foo, 10);first.join();second.join();return 0;
}/
// reference: http://www.cplusplus.com/reference/atomic/atomic_flag/clear/
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 test_atomic_flag_atomic_clear()
{// atomic_flag::clear: Clears the atomic_flag (i.e., sets it to false)//Clearing the atomic_flag makes the next call to member atomic_flag::test_and_set on this object return false.// The operation is atomic and follows the memory ordering specified by sync.// atomic_flag::test_and_set: Sets the atomic_flag and returns whether it was already set immediately before the call// The entire operation is atomic (an atomic read-modify-write operation): the value is not affected by other threads// between the instant its value is read (to be returned) and the moment it is modified by this function.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;
}} // namespace atomic
GitHub:https://github.com/fengbingchun/Messy_Test
?
總結
以上是生活随笔為你收集整理的C++11中头文件atomic的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++11中头文件thread的使用
- 下一篇: 协方差矩阵介绍及C++/OpenCV/E