C++11中头文件atomic的使用

2023-11-04

原子库为细粒度的原子操作提供组件,允许无锁并发编程。涉及同一对象的每个原子操作,相对于任何其他原子操作是不可分的。原子对象不具有数据竞争(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 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 test_atomic_atomic()
{
	// atomic::atomic: Constructs an atomic object
	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;
}

/
// 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 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 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 signal
	for (int i = 0; i<1000000; ++i) {}   // go!, count to 1 million
	if (!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 before
	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;
}

/
// 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_=0
		std::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 ordering
	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/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


GitHubhttps://github.com/fengbingchun/Messy_Test

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++11中头文件atomic的使用 的相关文章

  • 线程池EterfreeA/ThreadPool的使用

    在GitHub上有个线程池项目 地址为 https github com EterfreeA ThreadPool 开源 它的License为AFL 3 0 这里了解学习下 code中有较多的中文说明 1 Core hpp 一些define
  • C++11中enum class的使用

    枚举类型 enumeration 使我们可以将一组整型常量组织在一起 和类一样 每个枚举类型定义了一种新的类型 枚举属于字面值常量类型 C 包含两种枚举 限定作用域的和不限定作用域的 这里主要介绍限定作用域的 不限定作用域的使用可以参考 h
  • C++中的虚函数表介绍

    在C 语言中 当我们使用基类的引用或指针调用一个虚成员函数时会执行动态绑定 因为我们直到运行时才能知道到底调用了哪个版本的虚函数 所以所有虚函数都必须有定义 通常情况下 如果我们不使用某个函数 则无须为该函数提供定义 但是我们必须为每一个虚
  • C和C++安全编码笔记:整数安全

    5 1 整数安全导论 整数由包括0的自然数 0 1 2 3 和非零自然数的负数 1 2 3 构成 5 2 整数数据类型 整数类型提供了整数数学集合的一个有限子集的模型 一个具有整数类型的对象的值是附着在这个对象上的数学值 一个具有整数类型的
  • C++/C++11中头文件algorithm的使用

  • C和C++安全编码笔记:动态内存管理

    4 1 C内存管理 C标准内存管理函数 1 malloc size t size 分配size个字节 并返回一个指向分配的内存的指针 分配的内存未被初始化为一个已知值 2 aligned alloc size t alignment siz
  • 概率论中高斯分布(正态分布)介绍及C++11中std::normal_distribution的使用

    高斯分布 最常用的分布是正态分布 normal distribution 也称为高斯分布 Gaussian distribution 正态分布N x 2 呈现经典的 钟形曲线 的形状 其中中心峰的x坐标由 给出 峰的宽度受 控制 正态分布由
  • C++11中头文件atomic的使用

    原子库为细粒度的原子操作提供组件 允许无锁并发编程 涉及同一对象的每个原子操作 相对于任何其他原子操作是不可分的 原子对象不具有数据竞争 data race 原子类型对象的主要特点就是从不同线程访问不会导致数据竞争 因此从不同线程访问某个原
  • Windows下创建进程简介

    正在执行的应用程序称为进程 进程不仅仅是指令和数据 它还有状态 状态是保存在处理器寄存器中的一组值 如当前执行指令的地址 保存在内存中的值 以及唯一定义进程在任一时刻任务的所有其他值 进程与应用程序的一个重要的区别在于 进程运行时 进程的状
  • 提高C++性能的编程技术笔记:多线程内存池+测试代码

    为了使多个线程并发地分配和释放内存 必须在分配器方法中添加互斥锁 全局内存管理器 通过new 和delete 实现 是通用的 因此它的开销也非常大 因为单线程内存管理器要比多线程内存管理器快的多 所以如果要分配的大多数内存块限于单线程中使用
  • OpenCV代码提取:遍历指定目录下指定文件的实现

    OpenCV 3 1之前的版本 在contrib目录下有提供遍历文件的函数 用起来比较方便 但是在最新的OpenCV 3 1版本给去除掉了 为了以后使用方便 这里将OpenCV 2 4 9中相关的函数给提取了出来 适合在Windows 64
  • C语言中signal函数简介及使用

    signal h是C标准函数库中的信号处理部分 定义了程序执行时如何处理不同的信号 信号用作进程间通信 报告异常行为 如除零 用户的一些按键组合 如同时按下Ctrl与C键 产生信号SIGINT C 中的对应头文件是csignal C语言标准
  • 提高C++性能的编程技术笔记:引用计数+测试代码

    引用计数 reference counting 基本思想是将销毁对象的职责从客户端代码转移到对象本身 对象跟踪记录自身当前被引用的数目 在引用计数达到零时自行销毁 换句话说 对象不再被使用时自行销毁 引用计数和执行速度之间的关系是与上下文紧
  • C++中的内存对齐介绍

    网上有很多介绍字节对齐或数据对齐或内存对齐的文章 虽然名字不一样 但是介绍的内容大致都是相同的 这里以内存对齐相称 注 以下内容主要来自网络 内存对齐 通常也称为数据对齐 是计算机对数据类型合法地址做出了一些限制 要求某种类型对象的地址必须
  • C++中的封装、继承、多态

    封装 encapsulation 就是将抽象得到的数据和行为 或功能 相结合 形成一个有机的整体 也就是将数据与操作数据的源代码进行有机的结合 形成 类 其中数据和函数都是类的成员 封装的目的是增强安全性和简化编程 使用者不必了解具体的实现
  • C/C++中#pragma once的使用

    在C C 中 为了避免同一个文件被include多次 有两种方式 一种是 ifndef方式 一种是 pragma once方式 在头文件的最开始加入 ifndef SOME UNIQUE NAME HERE define SOME UNIQ
  • C++17中utf-8 character literal的使用

    一个形如42的值被称作字面值常量 literal 这样的值一望而知 每个字面值常量都对应一种数据类型 字面值常量的形式和值决定了它的数据类型 由单引号括起来的一个字符称为char型字面值 双引号括起来的零个或多个字符则构成字符串型字面值 字
  • C++中std::sort/std::stable_sort/std::partial_sort的区别及使用

    某些算法会重排容器中元素的顺序 如std sort 调用sort会重排输入序列中的元素 使之有序 它默认是利用元素类型的 lt 运算符来实现排序的 也可以重载sort的默认排序 即通过sort的第三个参数 此参数是一个谓词 predicat
  • C++/C++11中变长参数的使用

    C C 11中的变长参数可以应用在宏 函数 模板中 1 宏 在C99标准中 程序员可以使用变长参数的宏定义 变长参数的宏定义是指在宏定义中参数列表的最后一个参数为省略号 而预定义宏 VA ARGS 则可以在宏定义的实现部分替换省略号所代表的
  • 提高C++性能的编程技术笔记:单线程内存池+测试代码

    频繁地分配和回收内存会严重地降低程序的性能 性能降低的原因在于默认的内存管理是通用的 应用程序可能会以某种特定的方式使用内存 并且为不需要的功能付出性能上的代价 通过开发专用的内存管理器可以解决这个问题 对专用内存管理器的设计可以从多个角度

随机推荐

  • springboot 日志配置

    logback xml与logback spring xml 配置文件的加载顺序 logback xml gt application properties gt logback spring xml 如果同时存在logback xml和l
  • C#字符串数值前加0将1转化成01

    定义两个数值字符串 string str1 1 string str2 01 在我们的主观感受里这两个在进行数值比较时都是1 应该是等价的 但进行字符比对时则不尽然 转化处理 str1 Convert ToDouble str1 ToStr
  • oracle下载页面改版后的 JDK 下载、安装及其环境配置

    oracle下载页面改版后的 JDK 下载 安装及其环境配置 时间 2020 06 10 下载链接 https www oracle com java technologies javase downloads html 变量名 JAVA
  • Onnx推理框架

    Onnx推理框架 ONNX 即 Open Neural Network Exchange 当我们使用Pytorch或者TensorFlow训练完成后 通常会将其模型转化为ONNX模型 ONNX模型一般用于中间部署阶段 然后再拿转化后的ONN
  • Java的快速排序代码

    public static void quickSort int arr int start int end if start lt end int partitionIndex partition arr start end quickS
  • ETL学习心得:探求数据仓库关键环节ETL的本质

    原文链接 http hi baidu com horsewhite blog item b167f81f6924ef0a304e15a0 html 做数据仓库系统 ETL是关键的一环 说大了 ETL是数据整合解决方案 说小了 就是倒数据的工
  • spring系统架构

    一 ioc控制反转 业务层每次都要new一个新的对象来实现对实例的创建 耦合度偏高 使用IOC的最终目的是解除多个类之间的耦合性 降低代码的耦合度 IOC核心概念 ioc容器 spring容器 负责对象的创建 初始化等一系列工作 在ioc容
  • 【读书笔记】游戏开发原理

    游戏开发原理读书笔记 Contents 游戏开发原理读书笔记 一 游戏与游戏设计 1 游戏类型与平台 1 1 类型和子类型 1 2 出品类型 1 3 平台 1 4 图形类型 1 5 交付方式 1 6 视角 2 video game剖析 2
  • Unity3D之ForceMode模式

    ForceMode是一种在物理引擎中使用的模式 用于模拟对象之间的力和运动 它常用于游戏开发 虚拟现实和机器人学等领域 ForceMode通常应用于刚体 Rigidbody 对象 通过施加力来影响物体的运动 它提供了不同的模式 可以根据需求
  • gitee使用教程--初学者【超易懂】

    将本地文件上传至git 1 进入gitee官网 注册并登录 工作台 Gitee com 2 点击右上角加号 选择 新建仓库 3 给自己的仓库添加名称与项目描述 4 创建好之后会看到自己的仓库地址 5 在本地新建一个文件夹用来存放需要上传到g
  • 常量和标识符

    常量 常量是固定值 在程序执行期间不会改变 这些固定的值 又叫做字面量 常量可以是任何的基本数据类型 可分为整型数字 浮点数字 字符 字符串和布尔值 常量就像是常规的变量 只不过常量的值在定义后不能进行修改 在 C 中 有两种简单的定义常量
  • 用户端APP自动化测试_L2

    目录 appium server 环境安装 capability 进阶用法 元素定位工具 高级定位技巧 xpath 定位 高级定位技巧 css 定位与原生定位 特殊控件 toast 识别 显式等待高级使用 高级控件交互方法 设备交互api
  • sass中变量引入html,Sass变量、嵌套_html/css_WEB-ITnose

    声明变量 定义变量的语法 Sass 的变量包括三个部分 声明变量的符号 变量名称 赋予变量的值 简单的示例 假设你的按钮颜色可以给其声明几个变量 1 brand primary darken 428bca 6 5 default 337ab
  • rust使用rhai和actix实现web接口

    初始化项目 cargo new acix rhai web 依赖 Cargo toml package name actix sim yt version 0 1 0 edition 2021 See more keys and their
  • flutter图片显示

    图片显示 本地图片显示 首先项目根目录下创建一个用于放置图片的文件夹 将要显示的图片放进去 如下图 然后在项目根目录的pubspec yaml文件中的assets下添加图片路径 如下图 在需要显示图片的地方使用Image asset 进行加
  • 2021CCPC河南省省赛

    文章目录 1001 收集金币 1002 使用技能 1003 欢度佳节 1005 闯关游戏 1010 小凯的书架 1001 收集金币 题目链接 dp i 0 表示前i个事件都没有选择使用技能 dp i 1 表示前i个事件已经选择使用技能了 i
  • 关于Qt下中静态变量的使用

    需求是这样的 在主窗口类Widget中启动一个子线程去执行录音操作 然后使用共享的静态变量来结束录音 在Widget类中发出停止命令 MyThread类则停止录音操作 status定义 class MyThread public QObje
  • SparkStreaming从kafka消费数据

    val spark SparkSession builder master local appName myKafka getOrCreate 5秒一个窗口 val ssc new StreamingContext spark sparkC
  • ES6中数组首尾两端和中间添加/移除数据方法

    1 push 尾端插入 返回数组长度 let arr 1 hello true console log arr push 22 4 console log arr arr 1 hello true 22 console log arr pu
  • C++11中头文件atomic的使用

    原子库为细粒度的原子操作提供组件 允许无锁并发编程 涉及同一对象的每个原子操作 相对于任何其他原子操作是不可分的 原子对象不具有数据竞争 data race 原子类型对象的主要特点就是从不同线程访问不会导致数据竞争 因此从不同线程访问某个原