C++并发及互斥保护示例

        最近要写一个多线程的并发数据库,主要是希望使用读写锁实现库的并发访问,同时考虑到其他平台(如Iar)没有C++的读写锁,需要操作系统提供,就将读写锁封装起来。整个过程还是比较曲折的,碰到了不少问题,在此就简单分析总结下并发和互斥吧。

        首先,先贴上一部分源代码:

#include <shared_mutex>
#include <iostream>
#include <windows.h>
#include <synchapi.h>using cegn_mutex = std::shared_mutex;
cegn_mutex g_cegn_mutex;
void cegn_mutex_unique_lck(cegn_mutex& testmutex)	//独占锁,写数据
{std::unique_lock<cegn_mutex> cegn_lock(testmutex);
}void cegn_mutex_share_lck(cegn_mutex& Dbmutex)	//共享锁,读数据
{std::shared_lock<cegn_mutex> cegn_lock(Dbmutex);
}void cegn_mutex_unlck(cegn_mutex& Dbmutex)
{;	//vc读写锁离开作用域自动释放
}int g_dwVal = 0;
void FastWriteData(int i)
{while (1){cegn_mutex_unique_lck(g_cegn_mutex);g_dwVal++;std::cout << "FastWriteData " << "  Set dwVal= " << g_dwVal << "\n";Sleep(1000);cegn_mutex_unlck(g_cegn_mutex);}
}void SlowWriteData(int i)
{while (1){cegn_mutex_unique_lck(g_cegn_mutex);g_dwVal++;std::cout << "SlowWriteData " << " Set dwVal= " << g_dwVal << "\n";Sleep(5000);cegn_mutex_unlck(g_cegn_mutex);}
}void ReadData(int i)
{while (1){cegn_mutex_share_lck(g_cegn_mutex);std::cout << "ReadData " << " Get dwVal= " << g_dwVal << "\n";Sleep(500);cegn_mutex_unlck(g_cegn_mutex);}
}int main()
{std::cout << "main start !!" << std::endl;std::thread thread1 = std::thread(FastWriteData, 0);std::thread thread2 = std::thread(SlowWriteData, 0);thread1.join();thread2.join();getchar();return 1;
}

代码不长,逻辑也挺清晰的,但结果不正确:

似乎就没有互斥保护,因为FastWriteData和SlowWriteData中都独占了cegn_mutex_unique_lck(g_cegn_mutex);

且在while(1)中,不存在释放写锁的情况,那就不应该两个写线程交替出现。

如上让chatgpt分析下,它认为没啥问题,我尝试修改回标准读写锁接口,如下:

void FastWriteData(int i)
{while (1){
//		cegn_mutex_unique_lck(g_cegn_mutex);std::unique_lock<cegn_mutex> lck(g_cegn_mutex);g_dwVal++;std::cout << "FastWriteData " << "  Set dwVal= " << g_dwVal << "\n";Sleep(1000);cegn_mutex_unlck(g_cegn_mutex);}
}void SlowWriteData(int i)
{while (1){
//		cegn_mutex_unique_lck(g_cegn_mutex);std::unique_lock<cegn_mutex> lck(g_cegn_mutex);g_dwVal++;std::cout << "SlowWriteData " << " Set dwVal= " << g_dwVal << "\n";Sleep(5000);cegn_mutex_unlck(g_cegn_mutex);}
}

 如上,代码运行就是正常了

main start !!
FastWriteData   Set dwVal= 1
FastWriteData   Set dwVal= 2
FastWriteData   Set dwVal= 3
FastWriteData   Set dwVal= 4
FastWriteData   Set dwVal= 5
FastWriteData   Set dwVal= 6
FastWriteData   Set dwVal= 7
FastWriteData   Set dwVal= 8
FastWriteData   Set dwVal= 9
FastWriteData   Set dwVal= 10
FastWriteData   Set dwVal= 11
FastWriteData   Set dwVal= 12
FastWriteData   Set dwVal= 13
FastWriteData   Set dwVal= 14

现在FastWriteData就独占了互斥量,导致SlowWriteData无法运行。为啥使用接口:

void cegn_mutex_unique_lck(cegn_mutex& testmutex)    //独占锁,写数据
{
    std::unique_lock<cegn_mutex> cegn_lock(testmutex);
}

就不行了?

修改成直接调用:

using cegn_mutex = std::shared_mutex;
cegn_mutex g_cegn_mutex;
void cegn_mutex_unique_lck(cegn_mutex& testmutex)	//独占锁,写数据
{
//	std::unique_lock<cegn_mutex> cegn_lock(testmutex);std::unique_lock<cegn_mutex> cegn_lock(g_cegn_mutex);
}

还是不能正确互斥,修改如下也一样:

void cegn_mutex_unique_lck(cegn_mutex& testmutex)	//独占锁,写数据
{
//	std::unique_lock<cegn_mutex> cegn_lock(testmutex);std::unique_lock<std::shared_mutex> cegn_lock(g_cegn_mutex);
}

经过分析,问题是:

void cegn_mutex_unique_lck(cegn_mutex& testmutex)

函数中定义了一个互斥量cegn_lock :

std::unique_lock<cegn_mutex> cegn_lock(testmutex);

该互斥量在函数退出的时候,生命周期就结束了,所以自动销毁,最终导致无法互斥,那是在想要封装,如何实现呢,可以自己协议个类封装:

完整的简单代码如下:

#include <iostream>
#include <thread>
#include <mutex>
#include <windows.h>class MutexWrapper {
public:MutexWrapper(std::mutex& mutex) : m_mutex(mutex) {m_mutex.lock();}~MutexWrapper() {m_mutex.unlock();}private:std::mutex& m_mutex;
};std::mutex g_mutex_test;
int g_dwVal = 0;void FastWriteData(int i) {while (1) {MutexWrapper lock(g_mutex_test);g_dwVal++;std::cout << "FastWriteData " << "  Set dwVal= " << g_dwVal << "\n";Sleep(1000);}
}void SlowWriteData(int i) {while (1) {MutexWrapper lock(g_mutex_test);g_dwVal++;std::cout << "SlowWriteData " << " Set dwVal= " << g_dwVal << "\n";Sleep(3000);}
}int main() {std::cout << "main start !!" << std::endl;std::thread thread1 = std::thread(FastWriteData, 0);std::thread thread2 = std::thread(SlowWriteData, 0);thread1.join();thread2.join();getchar();return 1;
}

如此,运行正常了

修改下例程,让两个进程都整行跑 

void FastWriteData(int i) {while (1) {{MutexWrapper lock(g_mutex_test);g_dwVal++;std::cout << "FastWriteData " << "  Set dwVal= " << g_dwVal << "\n";}Sleep(1000);}
}void SlowWriteData(int i) {while (1) {{MutexWrapper lock(g_mutex_test);g_dwVal++;std::cout << "SlowWriteData " << " Set dwVal= " << g_dwVal << "\n";}Sleep(3000);}
}

如上,代码就基本都正常了。

当然,也可以将互斥锁修改为读写锁,如下:

class MutexWrapper {
public:MutexWrapper(std::shared_mutex& mutex) : m_mutex(mutex) {m_mutex.lock();}~MutexWrapper() {m_mutex.unlock();}private:std::shared_mutex& m_mutex;
};std::shared_mutex g_mutex_test;

代码也运行正常了。

综上:

1:基于RAII,C++的很多变量生命周期有限,必须特别注意智能变量的生命周期。

2:如果需要封装读写锁,不能简单函数分装,实在不行,就用一个类封装吧

3:要熟练掌握std::thread,std::shared_mutex,std::mutex的用法,这个是变法互斥基本要求

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络————IP数据报的首部各字段详解(很重要)

目录 1. IP数据报的介绍2. 首部的固定部分的各字段说明2.1 Version&#xff08;版本&#xff09;2.2 IHL&#xff08;首部长度&#xff09;2.3 Type of service&#xff08;区分服务&#xff09;2.4 Total Length&#xff08;总长度&#xff09;2.5 Identification&#xff08;…

http学习笔记3

第 11 章 Web 的攻击技术 11.1 针对 Web 的攻击技术 简单的 HTTP 协议本身并不存在安全性问题&#xff0c;因此协议本身几乎不会成为攻击的对象。应用 HTTP 协议的服务器和客户端&#xff0c;以及运行在服务器上的 Web 应用等资源才是攻击目标。目前&#xff0c;来自互联网的攻…

Python爬虫——scrapy_多条管道下载

定义管道类&#xff08;在pipelines.py里定义&#xff09; import urllib.requestclass DangDangDownloadPipelines:def process_item(self, item, spider):url http: item.get(src)filename ../books_img/ item.get(name) .jpgurllib.request.urlretrieve(url, filename…

js 小程序限流函数 return闭包函数执行不了

问题&#xff1a; 调用限流 &#xff0c;没走闭包的函数&#xff1a; checkBalanceReq&#xff08;&#xff09; loadsh.js // 限流 const throttle (fn, context, interval) > {console.log(">>>>cmm throttle", context, interval)let canRun…

django中使用ajax发送请求

1、ajax简单介绍 浏览器向网站发送请求时 是以URL和表单的形式提交的post 或get 请求&#xff0c;特点是&#xff1a;页面刷新 除此之外&#xff0c;也可以基于ajax向后台发送请求&#xff08;异步&#xff09; 依赖jQuery 编写ajax代码 $.ajax({url: "发送的地址"…

第十五课、Windows 下打包发布 Qt 应用程序

功能描述&#xff1a;讲解了 Windows 下打包发布 Qt 应用程序的三种方法&#xff0c;并对比优缺点 一、利用 windepolyqt 工具打包发布 Qt 提供了一个 windeployqt 工具来自动创建可部署的文件夹。 打包发布流程&#xff1a; 1. 新建一个文件夹&#xff0c;将编译后的可执行…

无涯教程-PHP - 循环语句

PHP中的循环用于执行相同的代码块指定的次数。 PHP支持以下四种循环类型。 for - 在代码块中循环指定的次数。 while - 如果且只要指定条件为真&#xff0c;就会循环遍历代码块。 do ... while - 循环执行一次代码块&#xf…

【解析postman工具的使用---基础篇】

postman前端请求详解 主界面1.常见类型的接口请求1.1 查询参数的接口请求1.1.1 什么是查询参数?1.1.2 postman如何请求 1.2 ❤表单类型的接口请求1.2.1 复习下http请求1.2.2❤ 什么是表单 1.3 上传文件的表单请求1.4❤ json类型的接口请求 2. 响应接口数据分析2.1 postman的响…

JVM详解

文章目录 一、JVM 执行流程二、类加载三、双亲委派模型四、垃圾回收机制&#xff08;GC&#xff09; 一、JVM 执行流程 程序在执行之前先要把java代码转换成字节码&#xff08;class文件&#xff09;&#xff0c;JVM 首先需要把字节码通过一定的方式 类加载器&#xff08;Clas…

数字孪生助力智慧水务:科技创新赋能水资源保护

智慧水务中&#xff0c;数字孪生有着深远的作用&#xff0c;正引领着水资源管理和环境保护的创新变革。随着城市化和工业化的不断推进&#xff0c;水资源的可持续利用和管理愈发显得重要&#xff0c;而数字孪生技术为解决这一挑战提供了独特的解决方案。 数字孪生技术&#xf…

ByteV联合“智农”打造的数字孪生高标准农田,助力乡村振兴!

ByteV联合“智农”打造的数字孪生高标准农田&#xff0c;不仅要让粮食稳产、增产&#xff0c;更要对土壤肥力进行改良和提升。不仅能够实现科技引领农业发展&#xff0c;更在智慧农业的基础上实现一站式托管&#xff0c;真正做到技术提升、5G引领、建后管护的闭环管理。让高标准…

无服务器架构发布啦!

导读Serverless 1.15.2 已发布。The Serverless Framework (无服务器架构&#xff09;允许你自动扩展、按执行付费、将事件驱动的功能部署到任何云。 目前支持 AWS Lambda、Apache OpenWhisk、Microsoft Azure&#xff0c;并且正在扩展以支持其他云提供商。 Serverless 降低了…

【c语言】五子棋(EasyX图形库+背景音乐)

大家好&#xff0c;有没有觉得写了好多c语言代码&#xff0c;面对的都是黑框框控制台&#xff0c;当我们学习了基础的c语言知识&#xff0c;和EasyX图形库后&#xff0c;终于可以和黑框框saygoodbye,今天要分享给大家的是小游戏五子棋&#xff0c;跟着小张一起学习吧 EasyX图形…

opencv-gpu版本编译(添加java支持,可选)实现硬解码

目录 opencv gpu版本编译&#xff0c;实现硬解码&#xff0c;加速rtsp视频流读取1、准备文件2、复制 NVCUVID 头文件到 cuda 安装目录 include3、安装相关依赖4、 执行cmake5、编译安装6、测试 opencv gpu版本编译&#xff0c;实现硬解码&#xff0c;加速rtsp视频流读取 前置条…

复习3-5天【80天学习完《深入理解计算机系统》】第七天

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

git创建分支和合并分支

1.创建分支 git创建分支只需要使用switch 命令就行&#xff1a; git switch -c 分支名 创建分支并切换到该分支 后面括号里面的内容发生改变就是修改了分支 。 然后想要合并分支就在 创建的分支中 进行提交修改的内容&#xff0c;还是通过&#xff1a;add 命令和commit命令…

6.链路追踪-Zipkin

链路追踪&#xff08;Distributed Tracing&#xff09;是一种用于监视分布式应用程序的技术&#xff0c;通过收集和展示分布式系统中不同组件之间的调用和交互情况&#xff0c;帮助开发人员和运维团队理解系统中的请求流程、性能瓶颈和异常情况。 1.Zipkin Zipkin 是一个开源的…

(三)行为模式:4、迭代器模式(Iterator Pattern)(C++示例)

1、迭代器模式&#xff08;Iterator Pattern&#xff09;含义 迭代器模式&#xff08;Iterator&#xff09;&#xff0c;提供一种方法顺序访问一个聚合对象中各个元素&#xff0c;而不暴露该对象的内部表示。【DP】 通过使用迭代器模式&#xff0c;可以将遍历算法与集合对象解耦…

C#程序变量统一管理例子 - 开源研究系列文章

今天讲讲关于C#应用程序中使用到的变量的统一管理的代码例子。 我们知道&#xff0c;在C#里使用变量&#xff0c;除了private私有变量外&#xff0c;程序中使用到的公共变量就需要进行统一的存放和管理。这里笔者使用到的公共变量管理库划分为&#xff1a;1)窗体&#xff1b;2)…

一“码”当先,PR大征集!2023 和RT-Thread一起赋能开源!

活动地址&#xff1a;https://club.rt-thread.org/ask/article/3c7cf7345ca47a18.html 活动介绍 「一“码”当先&#xff0c;PR大征集&#xff01;」是一项为了鼓励开发者积极参与开源软件开发维护的活动。 你可在Github RT-Thread&#xff08; https://github.com/RT-Thread …