C++11原子操作atomic

文章目录

    • 原子操作atomic
      • 原子操作的相关函数
      • 原子操作的特点
        • “平凡的”与“合格的”

原子操作atomic

前面我们介绍了互斥锁等一系列多线程相关操作,这里我们来说下原子操作atomic。
可以理解为原子变量就是将上面的操作进行了整合的一个全新变量,但是实际上它的原理和互斥锁不一样,这关系到操作系统的底层,我也不了解。

原子操作的相关函数

方法作用
is_lock_free检查原子对象是否免锁
load原子地获得原子对象的值
exchange原子地替换原子对象的值并获得它先前持有的值
compare_exchange_weak/compare_exchange_strong原子地比较原子对象与非原子实参的值,相等时进行原子交换,不相等时进行原子加载

除此之外,它还有写特化成员函数,我看了下好像不是很常用,就用到的时候再补充吧。这些函数中,用得多的可能就是load()和compare_exchange_weak(strong)()了。

原子操作的特点

这里就说说原子操作的特点吧:

  • 原子性:原子操作是不可分割的操作,要么完成整个操作,要么不进行操作。在多线程环境中,原子操作保证了共享数据的完整性
  • 线程安全:原子操作提供了线程安全的操作,多个线程可以同时执行原子操作而不会导致数据竞争或不一致的结果
  • 内存顺序:原子操作可以指定内存顺序,即操作的内存访问顺序。C++标准库提供了不同的内存顺序选项,可以控制原子操作的可见性和排序
  • 轻量级:原子操作是一种轻量级的同步机制,相比于锁或互斥量等其他同步机制,原子操作的开销更小
  • 支持不同的数据类型:C++原子操作可以用于不同的数据类型,包括整型、指针和标量类型等

原子性线程安全这两点是有关联的,原子性就保证了原子操作一定是线程安全的;但是内存顺序这点我不是很理解,应该需要计算机组成原理或者OS的相关知识。

在这里,我想要强调的是第三点:支持不同的数据类型
在学完条件变量之后,我写了一段简单的消息队列:

#include <iostream>
#include <thread>
#include <memory>
#include <string>
#include <condition_variable>
#include <list>
#include <atomic>

std::mutex mtx;
std::condition_variable cv;
std::list<std::string> msg;

// 读取数据
void read_thread(){
	while(true){
		std::unique_lock<std::mutex> lock(mtx);

		// 阻塞等待消息(并且解锁)
		// 有消息再执行,没消息不执行
		cv.wait(lock,[&](){ return !msg.empty(); });
		// 获取到互斥锁

		std::cout << "收到消息,解析中:" << std::endl;

		// 将数据从队列中取出
		std::cout << msg.front() << std::endl;
		msg.pop_front();
	}
}

// 写入数据
void write_thread(){
	std::cout << "请输入需要发送的数据:" << std::endl;
	std::string input;
	while(true){
		if(std::cin >> input){
			std::unique_lock<std::mutex> lock(mtx);
			// 将数据放入队列
			msg.push_back(input);
			std::cout << "数据成功输入" << std::endl;

			// 通知read线程,有消息可以接收
			cv.notify_all();
		}
	}
}

int main(){
	std::thread write_(write_thread);
	// 后台运行
	write_.detach();
	
	std::thread read_(read_thread);
	// 后台运行
	read_.detach();

	// 阻塞主线程
	while(true);

	return 0;
}

其中的重点就是条件变量互斥锁,当我学到原子操作的时候我就想:==我能不能将消息队列直接设定为原子操作呢?==于是就有了如下代码:

#include <atomic>
#include <list>
#include <thread>
#include <iostream>
#include <string>
#include <condition_variable>

std::atomic<std::list<std::string>> msg;
std::condition_variable cv;
std::mutex mtx;


void write_thread(){
	std::string input;
	while(true){
		if(std::cin >> input){
			std::cout << "请输入消息:" << std::endl;
			msg.load().emplace_back(input);
			cv.notify_one();
		}
	}
}

void read_thread(){
	while(true){
		std::unique_lock<std::mutex> lock(mtx);
		cv.wait(lock, [&](){ return !msg.load().empty(); });
		std::cout << "收到消息,正在解析:" << std::endl;
		std::cout << msg.load().front() << std::endl;
		msg.load().pop_front();
	}
}

int main(){
	std::thread write_(write_thread);
	write_.detach();

	std::thread read_(read_thread);
	read_.detach();

	while(true);
	return 0;
}

程序在写的时候没有报错提示,但是它跑不起来,有一个全新的报错信息:
在这里插入图片描述

至少我没看懂,同时终端给出了一个函数报错信息:
在这里插入图片描述

于是我就去查询C++参考手册,其中提到:
在这里插入图片描述

其他都差不多能看懂,主要问题就是在这个可平凡复制上,这个我也从来没有听说过,但是在其中出现了之前的报错函数。
于是我就顺着往下查,找到了关于可平凡复制类的说明:
在这里插入图片描述

根据这个说明,我才知道这个报错是因为std::string和std::list都不是可平凡复制类,所以出错了。

“平凡的”与“合格的”

在上面提供的信息中,我们其实还是不能够完全理解它是为什么,因为我们还不知道什么是平凡的
![[…/图片资源/C++/平凡的与合格的.png]]
从这里对“平凡的”的定义,我理解为:”平凡的“就是编译器默认提供的!,例如:C语言中的struct,我们是不能够去编写它的构造函数和析构函数的,相关的操作只有才C++中才支持。因此由编译器提供构造函数和析构函数struct类一定是“平凡的”。相对应的,C++中,由编译器提供构造函数和析构函数class类一般来说也是“平凡的“
并且,在C++中,提供了相应的函数用来评定一个类是否能够使用原子操作,也就是主模板中提到的五个函数:

  • 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

若是这五个函数的返回值有一个为false,就不能够使用原子操作。
对于原子操作,真的没有什么太多的内容,它就跟普通的变量差不了太多,只是它是原子的,具有线程安全的特性

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/231125.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Qt 容器QGroupBox带有标题的组框框架

控件简介 QGroupBox 小部件提供一个带有标题的组框框架。一般与一组或者是同类型的部件一起使用。教你会用,怎么用的强大就靠你了靓仔、靓妹。 用法示例 例 qgroupbox,组框示例(难度:简单),使用 3 个 QRadioButton 单选框按钮,与QVBoxLayout(垂直布局)来展示组框的…

远程控制如何赋能智能制造?贝锐向日葵制造业场景案例解析

随着数字化转型在制造业的不断深入&#xff0c;企业在产线端也逐渐投入更多智能化设备&#xff0c;数字化、智能化设备其中一个比较显著的优势就是可以依托互联网实现远程运维和调试&#xff0c;大大提升产线设备的稳定性和工作效率&#xff1b;而远程调试运维一个重要的实现方…

数据表排序

指针用的有点少了&#xff0c;有点不适应 用的冒泡排序 代码如下&#xff1a; #include<stdio.h> int num[100][100]; int * p[100], jud[100]; int judge(int i, int j, int rank); int m, n, k;int main(void) {scanf("%d%d%d", &m, &n, &k);f…

飞天使-linux操作的一些技巧与知识点

命令行光标移动到行首行尾 ctrl a 跳到首 ctrl e 跳到尾/etc/passwd rpm 包格式 RPM&#xff08;Red Hat Package Manager&#xff09;是一种常用的Linux软件包管理系统&#xff0c;它使用特定的命名规则来标识和命名软件包。RPM包的名称格式通常遵循以下规则&#xff1a;…

Flutter 开发问题摘要

系统&#xff1a;MacOS 14 开发工具&#xff1a;vscode Flutter版本&#xff1a;3.16.3 1.Error: To set up CocoaPods for ARM macOS, run: 解决方式&#xff1a; 在项目的ios文件目录下面执行下面的命令&#xff1a; arch -x86_64 pod install 执行结果&#xff1a;

SVPWM原理及simulink

关注微♥“电击小子程高兴的MATLAB小屋”获得专属优惠 一.SVPWM原理 SPWM常用于变频调速控制系统&#xff0c;经典的SPWM控制主要目的是使变频器的输出电压尽量接近正弦波&#xff0c;并未关注输出的电流波形。而矢量控制的最终目的是得到圆形的旋转磁场&#xff0c;这样就要求…

pr抖音素材42个手机竖屏抖音视频转场特效PR剪辑模板

酷炫、富有创意的Premiere Pro 视频转场动画过渡效果pr模板免费下载。增强内容演示、幻灯片、抖音、社交媒体广告、预告片、促销等视频画面切换效果。 来自PR模板网&#xff1a;https://prmuban.com/36404.html

TCP对数据的拆分

应用程序的数据一般都比较大&#xff0c;因此TCP会按照网络包的大小对数据进行拆分。 当发送缓冲区中的数据超过MSS的长度&#xff0c;数据会被以MSS长度为单位进行拆分&#xff0c;拆分出来的数据块被放进单独的网路包中。 根据发送缓冲区中的数据拆分情况&#xff0c;当判断…

12.8 作业

1&#xff0c; 使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin"&#…

PyQt6 QCalendarWidget日历控件

​锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计39条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话…

Python random模块及用法

random 模块主要包含生成伪随机数的各种功能变量和函数。 在 Python 的交互式解释器中先导入 random 模块&#xff0c;然后输入 random.__all__ 命令&#xff08;__all__ 变量代表了该模块开放的公开接口&#xff09;&#xff0c;即可看到该模块所包含的全部属性和函数&#x…

第二十一章网络通信总结

21.1 网络程序设计基础 Java网络程序设计基础涉及使用Java编程语言创建网络应用程序。这通常涉及到使用Java的网络API&#xff0c;如java.net包&#xff0c;以建立客户端和服务器之间的通信。 基本步骤包括&#xff1a; 1.创建服务器&#xff1a; 使用ServerSocket类创建服务…

Day05 linux高级系统设计 - 管道

复制文件描述符 dup函数 作用&#xff1a; 文件描述符复制 语法&#xff1a; #include <unistd.h> int dup (int oldfd); 参数&#xff1a; 所需复制得文件描述符 返回值&#xff1a; 复制到的文件描述符 功能&#xff1a; 从文件描述符表中&#xff0c;找一个最小…

SSH原理与应用与探索

Secure Shell(SSH 安全外壳协议) 是由 IETF(The Internet Engineering Task Force) 制定的建立在应用层基础上的安全网络协议。它是专为远程登录会话(甚至可以用Windows远程登录Linux服务器进行文件互传)和其他网络服务提供安全性的协议&#xff0c;可有效弥补网络中的漏洞。通…

Java预科知识

以下内容是根据狂神的Java说、chatgpt和csdn相关博客&#xff0c;结合自己的理解完成的。 Java了解 基于Java 开发了巨多的平台&#xff0c;系统&#xff0c;工具 构建工具&#xff1a; Ant, Maven, Jekins应用服务器&#xff1a;Tomcat, Jetty, Jboss, Websphere, weblogic…

vue的data

类型&#xff1a;Object | Function 限制&#xff1a;组件的定义只接受 function。 详细&#xff1a; Vue 实例的数据对象。Vue 会递归地把 data 的 property 转换为 getter/setter&#xff0c;从而让 data 的 property 能够响应数据变化。对象必须是纯粹的对象 (含有零个或多个…

vertica主键列能插入重复值的处理办法

问题描述 开发同事反馈在vertica中创建含主键列的表中插入重复数据时没有进行校验&#xff0c;插入重复值成功。经过测试着实可以插入重复值&#xff0c;这个坑有些不一样。 创建表和插入语句如下&#xff1a; --创建表 CREATE TABLE dhhtest(ID VARCHAR(64) PRIMARY KEY );…

快速认识什么是:Docker

Docker&#xff0c;一种可以将软件打包到容器中并在任何环境中可靠运行的工具。但什么是容器以及为什么需要容器呢&#xff1f;今天就来一起学快速入门一下Docker吧&#xff01;希望本文对您有所帮助。 假设您使用 Cobol 构建了一个在某种奇怪风格的 Linux 上运行的应用程序。您…

linux 定时任务

使用 crontab Usage: crontab [-u user] [-e|-l|-r] Crontab 的格式说明如下: * 逗号(‘,’) 指定列表值。如: “1,3,4,7,8″ * 中横线(‘-’) 指定范围值 如 “1-6″, 代表 “1,2,3,4,5,6″ * 星号 (‘*’) 代表所有可能的值 */15 表示每 15 分钟执行一次 # Use the ha…

Python中type、object和class的关系,一图即懂

没有文字描述&#xff0c;因为图足够好&#xff01; 查看一个类的基类可以使用__bases__方法查看一个实例对应的类是谁&#xff0c;可以用__class__方法 class Animal:pass class User:pass class Dog(Animal, User):passif __name__ "__main__":print(Dog.__bases…