C++中对共享数据的存取在并发条件下可能会引起data race的未定义行为,需要限制并发程序以某种特定的顺序执行,有两种方式:1.使用mutex保护共享数据; 2.原子操作
原子操作:针对原子类型操作要不一步完成,要么不做,不可能出现操作一半被切换CPU,这样防止由于多线程指令交叉执行带来的可能错误。非原子操作下,某个线程可能看见的是一个其它线程操作未完成的数据。
一、atomic_flag
std::atomic_flag是一个bool原子类型,有两个状态:set(flag=true) 和 clear(flag=false),必须被ATOMIC_FLAG_INIT初始化,此时flag为clear状态,相当于静态初始化。
一旦atomic_flag初始化后只有三个操作:test_and_set,clear,析构,均是原子化操作。
test_and_set检查flag是否被设置,若被设置直接返回true,若没有设置则设置flag为true后再返回false。
clear()清除flag标志即flag=false。
不支持拷贝、赋值等操作,这和所有atomic类型一样,因为两个原子类型之间操作不能保证原子化。atomic_flag的可操作性不强导致其应用局限性,还不如atomic<bool>。
使用atomic_flag作为简单的自旋锁例子:每个线程先将atomic_flag设为true,再设为false
atomic_flag lock_stream = ATOMIC_FLAG_INIT;//flag处于clear状态,没有被设置过 stringstream stream; void append_number(int x) { while (lock_stream.test_and_set()) {}//检查并设置是个原子操作,如以前没有设置过则退出循环, //每个线程都等待前面一个线程将lock_stream状态清楚后跳出循环,第一个线程除外,此时lock_stream为clear状态 stream << "thread #" << x << ' '; lock_stream.clear(); } int main() { vector<std::thread> threads; for (int i = 1; i <= 10; ++i) threads.push_back(thread(append_number, i)); for (auto& th : threads) th.join(); cout << stream.str(); system("pause"); return 0; }
二、 atomic<T>模板类
atomic<T>生成一个T类型的原子对象,并提供了系列原子操作函数。其中T是trivially copyable type,满足:要么全部定义了拷贝/移动/赋值函数,要么全部没定义;没有虚成员;基类或其它任何非static成员都是trivally copyable。典型的内置类型bool、int等属于trivally copyable。再如class triviall{public: int x};也是。
struct Node { int value; Node* next; Node(int val,Node* p):value(val),next(p){} }; atomic<Node*> list_head; void append(int val) { // append an element to the list Node* newNode = new Node(val,list_head ); // next is the same as: list_head = newNode, but in a thread-safe way: while (!list_head.compare_exchange_weak(newNode->next, newNode)) {} // (with newNode->next updated accordingly if some other thread just appended another node) } int main() { // spawn 10 threads to fill the linked list: vector<thread> threads; for (int i = 0; i<10; ++i) threads.push_back(thread(append, i)); for (auto& th : threads) th.join(); // print contents: for (Node* it = list_head; it != nullptr; it = it->next) cout << ' ' << it->value; std::cout << ' '; // cleanup: Node* it; while (it = list_head) { list_head = it->next; delete it; } system("pause"); return 0; }
http://blog.csdn.net/liuxuejiang158blog/article/details/17413149