atomic对int、char、bool等数据结构进行了原子性封装,在多线程环境中,对std::atomic对象的访问不会造成竞争-冒险。利用std::atomic可实现数据结构的无锁设计。
所谓的原子操作,取的就是“原子是最小的、不可分割的最小个体”的意义,它表示在多个线程访问同一个全局资源的时候,能够确保所有其他的线程都不在同一时间内访问相同的资源。也就是他确保了在同一时刻只有唯一的线程对这个资源进行访问。这有点类似互斥对象对共享资源的访问的保护,但是原子操作更加接近底层,因而效率更高。
在以往的C++标准中并没有对原子操作进行规定,我们往往是使用汇编语言,或者是借助第三方的线程库,例如intel的pthread来实现。在新标准C++11,引入了原子操作的概念,并通过这个新的头文件提供了多种原子操作数据类型,例如,atomic_bool,atomic_int等等,如果我们在多个线程中对这些类型的共享资源进行操作,编译器将保证这些操作都是原子性的,也就是说,确保任意时刻只有一个线程对这个资源进行访问,编译器将保证,多个线程访问这个共享资源的正确性。从而避免了锁的使用,提高了效率。
std::atomic_flag
std::atomic_flag是一个原子的布尔类型,可支持两种原子操作:
- test_and_set, 如果atomic_flag对象被设置,则返回true; 如果atomic_flag对象未被设置,则设置之,返回false
- clear. 清楚atomic_flag对象
std::atomic_flag可用于多线程之间的同步操作,类似于linux中的信号量。使用atomic_flag可实现mutex.
#include <iostream>
#include <atomic>
#include <vector>
#include <thread>
#include <sstream>
std::atomic_flag lock = ATOMIC_FLAG_INIT;
std::stringstream stream;
void append_numer(int x)
{
while (lock.test_and_set());
stream << "thread#" << x << "\n";
lock.clear();
}
int main()
{
std::vector<std::thread> ths;
for (int i=0; i<10; i++)
ths.push_back(std::thread(append_numer, i));
for (int i=0; i<10; i++)
ths[i].join();
std::cout << stream.str();
return 0;
}
std::atomic
std::atomic对int, char, bool等数据结构进行原子性封装,在多线程环境中,对std::atomic对象的访问不会造成竞争-冒险。利用std::atomic可实现数据结构的无锁设计。
#include <iostream>
#include <atomic>
#include <vector>
#include <thread>
#include <sstream>
std::atomic<bool> ready(false);
std::atomic_flag winner = ATOMIC_FLAG_INIT;
void count1m(int i)
{
while (!ready);
for (int i=0; i<1000000; i++);
if (!winner.test_and_set())
std::cout << "winner: " << i << std::endl;
}
int main()
{
std::vector<std::thread> ths;
for (int i=0; i<10; i++)
ths.push_back(std::thread(count1m, i));
ready = true;
for (int i=0; i<10; i++)
ths[i].join();
return 0;
}
成员函数 | 说明 |
store | 原子地以非原子对象替换原子对象的值 |
load | 原子地获得原子对象的值 |
特化成员函数 | 说明 |
fetch_add | 原子地将参数加到存储于原子对象的值,并返回先前保有的值 |
fetch_sub | 原子地进行参数和原子对象的值的逐位与,并获得先前保有的值 |
fetch_or | 原子地进行参数和原子对象的值的逐位或,并获得先前保有的值 |
fetch_xor | 原子地进行参数和原子对象的值的逐位异或,并获得先前保有的值 |
operator++ | 令原子值增加一 |
operator++(int) | 令原子值增加一 |
operator– | 令原子值减少一 |
operator–(int) | 令原子值减少一 |