走进C++11(三十七)原子操作之 std::atomic
关注公众号获取更多信息:
C++11提供了一个原子类型std::atomic<T>,可以使用任意类型作为模板参数,C++11内置了整型的原子变量,可以方便的使用原子变量,使用原子变量就不用互斥变量来保护该变量了。
每个 std::atomic 模板的实例化和全特化定义一个原子类型。若一个线程写入原子对象,同时另一线程从它读取,则行为良好定义(数据竞争的细节我们会在下节--内存模型里讲解)
另外,对原子对象的访问可以建立线程间同步,并按 std::memory_order 所对非原子内存访问定序。
需要注意的是,std::atomic 既不可复制亦不可移动。
由于std::atomic 是一个模板,C++11中定义了该模板特化的一些要求:
主模板
主 std::atomic 模板可用任何满足可复制构造 (CopyConstructible) 及可复制赋值 (CopyAssignable) 的可平凡复制 (TriviallyCopyable) 类型 T 特化。若下列任何值为 false 则程序为谬构:
std::is_trivially_copyable<T>::value
std::is_copy_constructible<T>::value
std::is_move_constructible<T>::value
std::is_copy_assignable<T>::value
std::is_move_assignable<T>::value
std::atomic<bool> 使用初等模板。它保证是标准布局结构体。
偏特化
标准库为下列类型提供 std::atomic 模板的特化,它们拥有初等模板所不拥有的额外属性:
对所有指针类型的部分特化 std::atomic<U*> 。这些特化拥有标准布局、平凡默认构造函数 (C++20 前)和平凡析构函数。除了为所有原子类型提供的操作,这些特化额外支持适合指针类型的原子算术运算,例如 fetch_add 、 fetch_sub 。
对整数类型的特化
以下列整数类型之一实例化时, std::atomic
提供适合于整数类型的额外原子操作,例如 fetch_add
、 fetch_sub
、 fetch_and
、 fetch_or
、 fetch_xor
:
字符类型 char 、 char8_t (C++20 起)、 char16_t 、 char32_t 和 wchar_t ;
标准有符号整数类型:signed char 、 short 、 int 、 long 和 long long ;
标准无符号整数类型:unsigned char 、 unsigned short 、 unsigned int 、 unsigned long 和 unsigned long long ;
任何头文件 <cstdint> 中的 typedef 所需的额外整数类型。
另外,结果的 std::atomic<Integral>
特化拥有标准布局、平凡默认构造函数 (C++20 前)和平凡析构函数。定义有符号整数算术为使用补码;无未定义结果。
atomic 用法
这次我们就不一一介绍atomic的API了,我们从atomic的定义反观atomic的用法:
template < class T > struct atomic {
bool is_lock_free() const volatile;
bool is_lock_free() const;
void store(T, memory_order = memory_order_seq_cst) volatile;
void store(T, memory_order = memory_order_seq_cst);
T load(memory_order = memory_order_seq_cst) const volatile;
T load(memory_order = memory_order_seq_cst) const;
operator T() const volatile;
operator T() const;
T exchange(T, memory_order = memory_order_seq_cst) volatile;
T exchange(T, memory_order = memory_order_seq_cst);
bool compare_exchange_weak(T &, T, memory_order, memory_order) volatile;
bool compare_exchange_weak(T &, T, memory_order, memory_order);
bool compare_exchange_strong(T &, T, memory_order, memory_order) volatile;
bool compare_exchange_strong(T &, T, memory_order, memory_order);
bool compare_exchange_weak(T &, T, memory_order = memory_order_seq_cst) volatile;
bool compare_exchange_weak(T &, T, memory_order = memory_order_seq_cst);
bool compare_exchange_strong(T &, T, memory_order = memory_order_seq_cst) volatile;
bool compare_exchange_strong(T &, T, memory_order = memory_order_seq_cst);
atomic() = default;
constexpr atomic(T);
atomic(const atomic &) = delete;
atomic & operator=(const atomic &) = delete;
atomic & operator=(const atomic &) volatile = delete;
T operator=(T) volatile;
T operator=(T);
};
可以看出,我们常用的API如下:
(构造函数) |
构造原子对象 (公开成员函数) |
operator= |
存储值于原子对象 (公开成员函数) |
is_lock_free |
检查原子对象是否免锁 (公开成员函数) |
store |
原子地以非原子对象替换原子对象的值 (公开成员函数) |
load |
原子地获得原子对象的值 (公开成员函数) |
operator T |
从原子对象加载值 (公开成员函数) |
exchange |
原子地替换原子对象的值并获得它先前持有的值 (公开成员函数) |
compare_exchange_weakcompare_exchange_strong |
原子地比较原子对象与非原子参数的值,若相等则进行交换,若不相等则进行加载 (公开成员函数) |
除了这些常用的API,我们常用的API还有一些特化的API(之前我们说过,只有整数类型和指针类型有特化,所以这些API只有整数类型和指针类型可用):
fetch_add |
原子地将参数加到存储于原子对象的值,并返回先前保有的值 (公开成员函数) |
fetch_sub |
原子地从存储于原子对象的值减去参数,并获得先前保有的值 (公开成员函数) |
fetch_and |
原子地进行参数和原子对象的值的逐位与,并获得先前保有的值 (公开成员函数) |
fetch_or |
原子地进行参数和原子对象的值的逐位或,并获得先前保有的值 (公开成员函数) |
fetch_xor |
原子地进行参数和原子对象的值的逐位异或,并获得先前保有的值 (公开成员函数) |
operator++operator++(int)operator--operator--(int) |
令原子值增加或减少一 (公开成员函数) |
operator+=operator-=operator&=operator|=operator^= |
加、减,或与原子值进行逐位与、或、异或 (公开成员函数) |
例子
下面我们用一个例子结束本文:
// 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;
}
可能的输出:
spawning 10 threads that count to 1 million...
thread #7 won!
走进C++11(三十七)原子操作之 std::atomic相关推荐
- C++11 并发指南六(atomic 类型详解三 std::atomic (续))
C++11 并发指南六( <atomic> 类型详解二 std::atomic ) 介绍了基本的原子类型 std::atomic 的用法,本节我会给大家介绍C++11 标准库中的 std: ...
- C++11 并发指南六( atomic 类型详解二 std::atomic )
C++11 并发指南六(atomic 类型详解一 atomic_flag 介绍) 一文介绍了 C++11 中最简单的原子类型 std::atomic_flag,但是 std::atomic_flag ...
- c++ 11 原子操作库 (std::atomic)(一)
定义于头文件 <atomic> atomic 类模板及其针对布尔.整型和指针类型的特化 template< class T > struct atomic; (1) (C ...
- c++ 11 原子操作库 (std::atomic)(二)
定义于头文件 <atomic> atomic 类模板及其针对布尔.整型和指针类型的特化 每个 std::atomic 模板的实例化和全特化定义一个原子类型.若一个线程写入原子对象,同时另一 ...
- unique函数_走进C++11(三十四)unique_ptr
std::unique_ptr是C++11标准中用来取代std::auto_ptr的指针容器(在C++11中,auto_ptr被废弃).它不能与其它unique_ptr类型的指针对象共享所指对象的内存 ...
- c+++11并发编程语言,C++11并发编程:多线程std:thread
原标题:C++11并发编程:多线程std:thread 一:概述 C++11引入了thread类,大大降低了多线程使用的复杂度,原先使用多线程只能用系统的API,无法解决跨平台问题,一套代码平台移植, ...
- 美学心得(第二百三十七集) 罗国正
美学心得(第二百三十七集) 罗国正 (2022年5月) 3023.中国伟大的科学家钱学森先生的这些观点,非常值得大家思考.研究,他说:"现代科学技术要分成八个大部门,它们是自然科学.社会 ...
- 【正点原子Linux连载】第三十七章 Linux内核移植 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0
1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...
- 第三十七章 Caché 命令大全 ZWRITE 命令
文章目录 第三十七章 Caché 命令大全 ZWRITE命令 重点 大纲 参数 描述 `ZWRITE`不带参数 `ZWRITE`带参数 Variables Non-Display Characters ...
最新文章
- ssh服务、密钥登陆配置
- javacurrentmap_Java ConcurrentHashMap.forEach方法代码示例
- 深入浅出Java核心技术开篇(总结)
- LIO-SAM探秘第三章之代码解析(五) --- imuPreintegration.cpp
- Nginx_PHP缓存设置的整理对比
- MacbookAir2011用U盘重装10.13.6High Sierra系统
- 用计算机绘制颗粒级配曲线,EXcel如何绘制颗粒级配曲线图
- mysql geometry查询返回值_使用MySQL的geometry类型处理经纬度距离问题的方法
- List集合过滤不符合条件的数据
- node进程cpu 100%问题排查
- 51单片机和315M无线发射模块编码与解码
- 牛客小白月赛21 I	I love you(dp的优化)
- 【微信支付】APP支付和APIJS支付
- 【Java接口】限制App登录次数
- 对JAVA多态的理解
- openVPN服务端搭建
- strcasecmp与stricmp
- 一个人下班后,如何高质量提升自己
- Dmaven.multiModuleProjectDirectory system property is not set
- 匹兹堡Mac高清动态壁纸