C++原子操作和互斥锁性能(速度)对比

news2024/11/24 8:47:45

先说结论:原子操作性能(速度)强于互斥锁,下面用例子进行说明。

 编写测试demo,开启两个线程,对全局变量n分别进行自增、自减操作,计算执行时间。

首先看没有用任何手段进行互斥的情况,用文章《C++计算打印函数和代码块的执行时间(支持所有类型函数)》中的方法进行时间测量:

#include <atomic>
#include <thread>
#include <chrono>
#include <memory>
#include <future>
#include <functional>
#include <iostream>

using namespace std;
#define TOTAL 100000000
int n = 0;


template<class T, class... Args>
auto measure(T&& func, Args&&... args)->std::future<typename std::result_of<T(Args...)>::type>
{
    using return_type = typename std::result_of<T(Args...)>::type;
    auto task = std::make_shared<std::packaged_task<return_type()>>
        (std::bind(std::forward<T>(func), std::forward<Args>(args)...));
    std::future<return_type> res = task->get_future();
    auto begin = std::chrono::high_resolution_clock::now();
    (*task)();
    auto end = std::chrono::high_resolution_clock::now();
    auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin);
    printf("执行时间: % .3f seconds.\n", elapsed.count() * 1e-9);
    return res;
}


void funPlus()
{
    for (int i = 0; i < TOTAL; i++)
    {
        n++;
    }
}

void funMinus()
{
    for (int i = 0; i < TOTAL; i++)
    {
        n--;
    }
}

int main()
{
    measure([] {
        thread a(funPlus);
        thread b(funMinus);
        a.join();
        b.join();
        });

    cout << "执行结束,n的值为: " << n << endl;
	return 0;
}

运行结果如下:

执行时间是0.541秒,是耗时最短的,但是由于没有用互斥方法保护,所以临界资源n的值不正确(正确的值应该为0)。这是因为自增、自减操作不是原子的,编译得到的汇编指令可能会对应多条指令。所以我们得要对n这个临界资源进行互斥保护。

我们来看下使用原子操作std::atomic

#include <atomic>
#include <thread>
#include <chrono>
#include <memory>
#include <future>
#include <functional>
#include <iostream>

using namespace std;
#define TOTAL 100000000
atomic<int> n(0);


template<class T, class... Args>
auto measure(T&& func, Args&&... args)->std::future<typename std::result_of<T(Args...)>::type>
{
    using return_type = typename std::result_of<T(Args...)>::type;
    auto task = std::make_shared<std::packaged_task<return_type()>>
        (std::bind(std::forward<T>(func), std::forward<Args>(args)...));
    std::future<return_type> res = task->get_future();
    auto begin = std::chrono::high_resolution_clock::now();
    (*task)();
    auto end = std::chrono::high_resolution_clock::now();
    auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin);
    printf("执行时间: % .3f seconds.\n", elapsed.count() * 1e-9);
    return res;
}


void funPlus()
{
    for (int i = 0; i < TOTAL; i++)
    {
        n++;
    }
}

void funMinus()
{
    for (int i = 0; i < TOTAL; i++)
    {
        n--;
    }
}

int main()
{
    measure([] {
        thread a(funPlus);
        thread b(funMinus);
        a.join();
        b.join();
        });

    cout << "执行结束,n的值为: " << n << endl;
	return 0;
}

执行效果如下:

 可以看到耗时为:5.261秒,n的值为0。也就是说耗时变长了,但是临界资源n的值可以保证 一定正确。

我们再来看使用互斥锁的情况:

#include <atomic>
#include <thread>
#include <chrono>
#include <memory>
#include <future>
#include <functional>
#include <iostream>
#include <mutex>

using namespace std;
#define TOTAL 100000000
std::mutex g_mutex;
int n = 0;


template<class T, class... Args>
auto measure(T&& func, Args&&... args)->std::future<typename std::result_of<T(Args...)>::type>
{
    using return_type = typename std::result_of<T(Args...)>::type;
    auto task = std::make_shared<std::packaged_task<return_type()>>
        (std::bind(std::forward<T>(func), std::forward<Args>(args)...));
    std::future<return_type> res = task->get_future();
    auto begin = std::chrono::high_resolution_clock::now();
    (*task)();
    auto end = std::chrono::high_resolution_clock::now();
    auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin);
    printf("执行时间: % .3f seconds.\n", elapsed.count() * 1e-9);
    return res;
}


void funPlus()
{
    for (int i = 0; i < TOTAL; i++)
    {
        std::lock_guard<std::mutex> lock(g_mutex);
        n++;
    }
}

void funMinus()
{
    for (int i = 0; i < TOTAL; i++)
    {
        std::lock_guard<std::mutex> lock(g_mutex);
        n--;
    }
}

int main()
{
    measure([] {
        thread a(funPlus);
        thread b(funMinus);
        a.join();
        b.join();
        });

    cout << "执行结束,n的值为: " << n << endl;
	return 0;
}

运行效果如下:

可以看到执行时间为27.762秒。执行时间最长,但也能保持临界资源n的值正确。

所以对于基本类型的临界资源,我们进行访问时可以用原子操作代替互斥锁,来提高性能。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Springboot生成Word/EXECL/PPTX文档

目录 一、概述 二、使用介绍 第一种Poi-tl&#xff1a; 1、介绍 2、功能 第二种Poi: 什么是POI 二进制分布 源码分发 一、概述 Word模板引擎&#xff1a;使用Word模板和数据生成对应的Word文档。 方案移植性功能性易用性 Poi-tl Java跨平台 Word模板引擎&#…

【uniapp小程序】路由跳转navigator传参封装

文章目录&#x1f34d;前言&#x1f34b;正文1、看官网1.1 navigator API 介绍1.2、路由跳转参数传递1.3、五种常见的跳转方式1.3.1 uni.navigateTo(OBJECT)1.3.2 uni.redirectTo(OBJECT)1.3.3 uni.reLaunch(OBJECT)1.3.4 uni.switchTab(OBJECT)1.3.5 uni.navigateBack(OBJECT)…

Ensp用windows回环口连接cloud配置

Ensp模拟通过本机&#xff08;windows&#xff09;用python脚本批量配置华为数通设备时&#xff0c;为了避免对内网资源的浪费最好用回环口&#xff08;loopback&#xff09;。 一、windows开启loopback虚拟接口 概要&#xff1a; right click on window start menu icon an…

【C++】类型转换

目录 一、C语言风格类型转换 二、C风格类型转换 1.static_case 2.reinterpret_case 3、const_case 4、dynamic_case 三、RTTI 总结 一、C语言风格类型转换 在C语言中&#xff0c;如果赋值运算符左右两侧类型不同&#xff0c;或者形参与实参类型不匹配&#xff0c;或者返…

N-Gram模型介绍

N-gram是一种基于统计语言模型的算法&#xff0c;基本思想是将文本内容按照字节进行大小为N的滑动窗口操作&#xff0c;形成了长度是N的字节片段序列。 每一个字节片段称为gram&#xff0c;对所有gram的出现频度进行统计&#xff0c;并且按照事先设定好的阈值进行过滤&#xf…

PowerQuery:使用正则表达式

博客来源于我的语雀专栏&#xff1a;R 语言 语雀 更多内容同步更新请关注我的语雀&#xff1a;令平子 语雀 参考资料&#xff1a;部分已引用到各段落 在Power Query中使用正则表达式 Power query 自定义正则表达式函数 新建空白查询&#xff0c;粘贴以下代码&#xff0c;使用…

gcc: error trying to exec ‘cc1plus‘: execvp: no such file or directory

该问题是缺少gcc文件&#xff0c;或者gcc与g版本不匹配问题 问题来源1&#xff1a;系统文件的缺失或者不匹配 按照如下方法测试 安装主要是利用apt-get安装&#xff0c;如果没有root权限的话&#xff0c;只能下载源码进行编译安装&#xff0c;然后添加路径环境&#xff0c;安…

JavaWeb简单实例——Ajax请求

简单介绍&#xff1a; 在上一章节我们展示了关于jQuery的一些基本操作&#xff0c;接下来我们就要进行Ajax的一些基础操作&#xff0c;在真正执行操作之前&#xff0c;我们还需要一点前置的准备&#xff0c;就是关于发送和请求JSON数据的准备。 请求JSON数据&#xff1a; JS…

板卡测评 | 基于TI AM5708开发板——ARM+DSP多核异构开发案例分享

本次测评板卡是创龙科技旗下的TL570x-EVM,它是一款基于TI Sitara系列AM5708ARM Cortex-A15+浮点DSPC66x处理器设计的异构多核SOC评估板,由核心板和评估底板组成。核心板经过专业的PCB Layout和高低温测试验证,稳定可靠,可满足各种工业应用环境。 评估板接口资源丰富,引出…

你还不懂《顺序表》?那就不要错过这篇文章!!!

&#x1f387;&#x1f387;&#x1f387;作者&#xff1a; 小鱼不会骑车 &#x1f386;&#x1f386;&#x1f386;专栏&#xff1a; 《java练级之旅》 &#x1f393;&#x1f393;&#x1f393;个人简介&#xff1a; 一名专科大一在读的小比特&#xff0c;努力学习编程是我…

怎样翻译文本?这三种翻译方法我经常使用

大家是不是还在将收到的文本或资料一句一句地复制到浏览器去翻译&#xff0c;再将翻译结果粘贴回文内呢&#xff1f;这种方法固然可以&#xff0c;但要是遇到需要翻译的文本内容比较多的情况时&#xff0c;就会很浪费时间和精力&#xff0c;如果恰好被英语不好的小伙伴遇到这种…

NoSQL数据库之Redis2

Redis 事务 事务的基础概念 关于事务最常见的例子就是银行转账&#xff0c;A 账户给 B 账户转账一个亿 (T1)&#xff0c;买一块地盖房子。在这种交易的过程中&#xff0c;有几个问题值得思考&#xff1a; 如何同时保证上述交易中&#xff0c;A账户总金额减少一个亿&#xff…

[附源码]Python计算机毕业设计Django的毕业生就业系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

蜂鸟E203学习笔记(四)——取指

1.1 取值概述 1.1.1 如何快速取指 首先要保证存储器的读延时足够小&#xff0c;通常使用指令紧耦合存储器&#xff08;ITCM&#xff09;和指令缓存器&#xff08;ICache&#xff09;。 ITCM通常使用离处理核很近的SRAM因此实现极短的延时。但是没有过大的存储空间&#xff0…

社区系统项目复盘-2

文章目录登录模块注册登录账号设置登录模块 重要知识点&#xff1a; ThreadLocal&#xff0c;Hostholder采用Threadlocal持有用户信息&#xff0c;用于代替session对象 ThreadLocal采用线程隔离的方式存放数据&#xff0c;可以避免多线程之间出现数据访问冲突。ThreadLocal提…

小程序全局配置文件以及常用配置项

一、window常用配置 1.小程序根目录下的app.json文件时小程序的全局配置文件。常用配置项如下&#xff1a; ① pages 记录当前小程序所有页面的存放路径 ② window 全局设置小程序窗口的外观 ③ tabBar 设置小程序底部的tabBar效果 ④ style 是否启用新版的组件样式 …

【Spring项目中的Service理解】

目录 1. Spring项目中的核心组成部分 2. Spring项目中的Service 2.1 Service的功能作用 2.2 Service的实现 1. Spring项目中的核心组成部分 项目的核心组成部分图解&#xff1a; 2. Spring项目中的Service 2.1 Service的功能作用 Service是项目中用于处理业务逻辑的&#x…

【学习笔记66】JavaScript的深浅拷贝

一、赋值 只要是引用数据类型, 那么在赋值的时候, 就是引用地址的传递// 赋值:字符串const s1 123;let s2 s1; // 赋值console.log(s2 s1); // trues2 456;console.log(s1); // 123console.log(s2); // 456 let o1 { a: 1 };let o2 o1; // 赋值console.log…

【iOS】—— GET和POST以及AFNetworking框架

GET和POST以及AFNetworking框架 文章目录GET和POST以及AFNetworking框架GET和POSTGET和POST区别GETGET请求步骤GET请求代码POSTPOST请求步骤POST请求代码AFNetworking简介添加头文件GETGET方法GET方法参数GET方法代码样例POSTPOST方法第一种&#xff1a;第二种&#xff1a;先来…

[附源码]计算机毕业设计springboot防疫物资捐赠

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…