当前位置: 首页 > news >正文

c++原子操作

原子操作,顾名思义,该操作不可分割。多线程环境也能保证读写数据不错乱。百度搜索了下,其核心概念如下:

1、不可分割性。原子操作是指一系列不可被CPU上下文交换的机器指令,操作要么完全执行,要么完全不执行,其他线程无法观察到中间状态‌。

2、可见性和顺序性。原子操作确保对变量的修改在所有线程中立即可见,并可通过内存顺序(如memory_order_relaxedmemory_order_seq_cst)控制操作的全局顺序一致性‌。

为了验证上面结论,测试下。 下面是开启10个线程执行同一个函数,将一个变量增加10000次,最终期望该变量值为100000,代码如下:

#include <iostream>
#include "listNode.h"
#include "solution.h"
#include <algorithm>
#include <unordered_set>
#include <unordered_map>
#include <map>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include "solution3.h"
#include "dataDefine.h"
#include "uthash.h"
#include "IntArrayList.h"
#include <string.h>
#include <thread>
#include <atomic>static std::atomic<int> count2{0};  // 原子整型
// 或这样写:
//static std::atomic<int> count2(0);void task2(int id) {for (auto i = 0; i < 10000; i++) {count2.fetch_add(1); // 值自增1}cout << "id:" << id << ", threadID:" << std::this_thread::get_id() << "  finish" << endl;
}void testTread2() {vector<thread> threads;for (auto i = 0; i < 10; i++) {thread t(task2, i); // i是task2函数的参数threads.emplace_back(std::move(t)); // 线程不可拷贝,只能移动。不能直接传t, 或者直接这样:threads.emplace_back(task2, i);}for (auto& t : threads) {//cout << "thread id: " << t.get_id() << " invoke join in" << endl;t.join(); // 当前线程(即主线程)等待这个线程执行完毕。}cout << "count2 value: " << count2 << endl;
}int main() {testTread2();
}

测试结果:

ok! 和预期结果一致。

再测试下非原子操作。下面操作是开启10个线程执行同一个函数,将一个变量增加10000次,最终期望该变量值为100000, 代码示例:

#include <iostream>
#include "listNode.h"
#include "solution.h"
#include <algorithm>
#include <unordered_set>
#include <unordered_map>
#include <map>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include "solution3.h"
#include "dataDefine.h"
#include "uthash.h"
#include "IntArrayList.h"
#include <string.h>
#include <thread>
#include <atomic>static auto count1 = 0;
void task1(int id) {for (auto i = 0; i < 10000; i++) {count1++;}cout << "id:" << id << ", threadID:" << std::this_thread::get_id() << "  finish" << endl;
}void testTread1() {vector<thread> threads;for (auto i = 0; i < 20; i++) {threads.emplace_back(task1, i);  // i是task1函数的参数// 或者这样构造一个线程//thread t(task1, i);}for (auto& t : threads) {//cout << "thread id: " << t.get_id() << " invoke join in" << endl;t.join(); // 当前线程(即主线程)等待这个线程执行完毕。}cout << "count1 value: " << count1 << endl;
}int main() {testTread1();
}

测试打印结果:

打印 count1 value:92243, 和期望值不一致,每次执行结果都是不确定的值。而且日志也打印的乱糟糟。

结论:非原子操作,以上示例,多线程调用同一个函数,没有对线程进行同步, 导致读写数据错乱,比如线程1读取该变量值为10, 可能同时线程2也读取到该变量值为10,然后都加1,结果变量值变为11被写回。所以最终结果会小于预期值。

相关文章:

  • Day09 【基于LSTM实现文本加标点的任务】
  • # 手写数字识别:使用PyTorch构建MNIST分类器
  • AI赋能智能经营:全球关税战下的可持续发展之道
  • 2000-2019年各省城市液化石油气用气人口数据
  • 人工智能概念股投资:10大潜力标的深度研究
  • AutoDL上Xinference安装
  • JVM-基于Hotspot
  • JVM 调优不再难:AI 工具自动生成内存优化方案
  • 【bash】.bashrc
  • PhotoShop学习10
  • 分享:批量提取图片文字并自动命名文件,ocr识别图片指定区域并重命名文件名工具,基于WPF和腾讯OCR识别的接口的视线方案
  • 数据库ALGORITHM = INSTANT研究过程
  • 【正点原子STM32MP257连载】第四章 ATK-DLMP257B功能测试——A35M33异核通信测试
  • 驱动学习专栏--字符设备驱动篇--2_字符设备注册与注销
  • 《What Are Step-Level Reward Models Rewarding?》全文翻译
  • Tecnomatix Plant Simulation 2302安装教程
  • 大模型微调新阵地:魔塔社区(Swift框架) 的探索与使用
  • 基于LLVM设计领域专用语言(DSL)的步骤——以激光微加工为例
  • 制作一款打飞机游戏教程7:爆炸
  • Qt 的 事件队列
  • 小程序制作流程微信/河北百度竞价优化
  • 荆门网站建设公司/免费html网站模板
  • 做教育网站多少钱/seo营销策略
  • 做逆战网站的名字/创建个人网站的流程
  • 安阳网站建设公司/今日新闻头条官网
  • 广州技术支持 奇亿网站建设/专业恶意点击软件