C++原子操作与内存序 1

这篇具有很好参考价值的文章主要介绍了C++原子操作与内存序 1。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

问题

#include<iostream>
#include<thread>
int main()
{
	int sum = 0;
	auto f = [&sum]() {
		for (int i = 0; i < 10000; i++)
			sum += 1;
	};
	std::thread t1(f);
	std::thread t2(f);

	t1.join();
	t2.join();
	std::cout << "the sum of 2 threads is: " << sum << std::endl;
	std::cin.get();
	return 0;
}

这个程序只是简单的通过两个线程对同一个变量进行累加10000次,正常不管线程执行的先后顺序,结果都应该是20000才对,可实际输出结果如图所示,程序的输出3次的结果都不一样,不一定是预期的20000;

C++原子操作与内存序 1

分析

对于+1操作,具体执行可以分为3个操作,如下图所示:
C++原子操作与内存序 1

可以看出问题发生在两个线程写的时候,如线程1刚写完,线程2继续写,则丢失一次加法。所以得出的值往往小于20000。

解决

可以通过std::mutex加锁对变量操作进行保护,有没有不用锁也能实现的呢?C++中提供了原子操作可以实现这一目标。

代码如下:

	std::atomic<int> sum1 = 0;
	auto f1 = [&sum1]() {
		for (int i = 0; i < 10000; i++)
			sum1+=1;
	};

	std::thread t3(f1);
	std::thread t4(f1);

	t3.join();
	t4.join();
	std::cout << "the sum of 2 threads with atomic is: " << sum1 << std::endl;
输出如下:

C++原子操作与内存序 1
可以看出未原子化的sum仍然是每次结果不尽相同,而原子化的sum1每次结果都为20000。
所谓原子操作指的是不可分割的操作,可以理解为只能编译成一条单独的CPU执行指令,不可以再分解,C++中,基本通过原子类型来实现原子操作。这种原子类型为std::atomic<T>,其中模板参数T为基本的数据类型,如bool,char,int,指针等。
程序中将sum1原子化,并调用+=操作符(已重载为原子操作),之前分解的3步成了不可分割的1步,所以不会出现两个线程同时已经进入写的状态,进而能保证累加结果的正确。

注意事项

  1. 若累加操作改为sum1=sum1+1,就不是原子操作了,结果与sum没有差别

  2. int型++/+=是原子操作fetch_add()的重载,类似的还有fetch_sub()/fetch_and/fetch_or()/fetch_xor()
    文章来源地址https://www.toymoban.com/news/detail-844178.html

到了这里,关于C++原子操作与内存序 1的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • THRUST:一个开源的、面向异构系统的并行编程语言:编程模型主要包括:数据并行性、任务并行性、内存管理、内存访问控制、原子操作、同步机制、错误处理机制、混合编程模型、运行时系统等

    作者:禅与计算机程序设计艺术 https://github.com/NVIDIA/thrust 2021年8月,当代科技巨头Facebook宣布其开发了名为THRUST的高性能计算语言,可用于在设备、集群和云环境中进行并行计算。它具有“易于学习”、“简单易用”等特征,正在逐步取代C++、CUDA、OpenCL等传统编程模型,成为

    2024年02月07日
    浏览(50)
  • C++ map clear内存泄漏问题

    map自带的clear()函数会清空map里存储的所有内容,但如果map值存储的是指针,则里面的值不会被清空,会造成内存泄漏,所以值为指针的map必须用迭代器清空。 使用erase迭代删除 迭代器删除值为指针的map,一定要注意迭代器使用正确,一旦迭代器失效程序就会崩溃。 调用cle

    2024年02月09日
    浏览(37)
  • C++内存分配揭秘:new操作符::operator new和Placement new的区别

      在 C++ 中, new  操作符、 ::operator new  和 placement new 是用于动态内存分配的工具,但它们有不同的用法和行为。以下是它们的区别和用法的详细实例: new  操作符用于在堆上动态分配内存,并调用对象的构造函数初始化对象。 ::operator new  是 C++ 中的全局函数,用于分配内

    2024年01月18日
    浏览(35)
  • 6.3 C++11 原子操作与原子类型

    在C++中,一个全局数据在多个线程中被同时使用时,如果不加任何处理,则会出现数据同步的问题。 上述例子中test函数对全局变量val进行累加,并在thread1和thread2两个线程中分别处理test函数。得到的结果如下: val的值并不是期望的20000000,这是因为val++操作不是原子操作导致

    2024年02月04日
    浏览(27)
  • c#向c++(opencv)实现双向图像数据传递,以及内存空间申请与释放问题

    c++与c#之间对应的数据关系: https://blog.csdn.net/qq_44544908/article/details/128784250 c++转换到c#的辅助工具(推荐,可以自动按照输入的c++代码函数或结构体转换为c#代码段): https://codeload.github.com/jaredpar/pinvoke-interop-assistant/zip/refs/heads/master 数据转换的基本依据: 一个数据有两个特征:

    2024年02月12日
    浏览(42)
  • 并发编程08:原子操作类

    Atomic 翻译成中文是原子的意思。在化学上,我们知道原子是构成一般物质的最小单位,在化学反应中是不可分割的。在我们这里 Atomic 是指一个操作是不可中断的。即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰。 AtomicInteger :整型原子类 At

    2024年02月04日
    浏览(39)
  • 原子操作的原理和实现

    目录 相关术语 处理器如何实现原子操作 Java如何实现原子操作 循环CAS实现原子操作 使用锁机制实现原子操作 原子操作是指一个或者多个不可再分割的操作。这些操作的执行顺序不能被打乱。 缓存行 :缓存的最小操作单位 (面试题、重点)比较并且交换(CAS) :CAS操作(

    2024年02月10日
    浏览(29)
  • AXI之原子操作

    原子 ,可以认为是物质组成的最小单位,当然,现在科学表明,比原子小的还有质子和中子。但是这里我们还将原子作为最小单位来理解,那么原子就是不可分割的,因此原子操作就可以理解为不可分割的操作。 AXI的原子操作包括exclusive和lock两种,不管是exclusive还是lock操作

    2024年02月10日
    浏览(33)
  • 原子操作CAS

    悲观锁 具有强烈的独占和排他特性。在有悲观锁的情况下,对数据进行处理,数据会处于锁定状态。前面讲到的synchronized同一时间 只允许一个线程访问某块资源 ,其他线程处于阻塞状态,就是一个独占锁,是悲观锁中的一种。 悲观锁适用于写操作比较多的场景。 乐观锁 对

    2024年02月13日
    浏览(34)
  • 近4w字吐血整理!只要你认真看完【C++编程核心知识】分分钟吊打面试官(包含:内存、函数、引用、类与对象、文件操作)

    🌈个人主页:godspeed_lucip 🔥 系列专栏:C++从基础到进阶 🏆🏆关注博主,随时获取更多关于C++的优质内容!🏆🏆 🍉配套markdown文件下载:请翻阅至文章底部获取 本阶段主要针对C++ 面向对象 编程技术做详细讲解,探讨C++中的核心和精髓。 C++程序在执行时,将内存大方向划

    2024年01月17日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包