【文件锁】多进程线程安全访问文件demo

组合文件锁+共享锁,并RAII 化,保证文件的跨进程线程读写安全。
demo模拟使用多个进程,每个进程包含多个线程对文件进行读写测试。
代码调用开源json库,需要下载到调试机器,编译时手动指定:

g++ -std=c++17 -pthread dbug.cpp  -I/root/json/include 
#include <cstddef>
#include <cstdlib>
#include <unistd.h>
#include <fstream>
#include <sys/stat.h>
#include <filesystem>
#include <iomanip>#include <sys/wait.h>
#include <iostream>
#include <thread>
#include <vector>
#include <chrono>
#include <unordered_map>
#include <memory>
#include <string>
#include <fcntl.h>
#include <sys/file.h> // 包含文件锁相关的头文件
#include <sys/types.h>
#include <sys/wait.h>
#include <mutex>  // 包含mutex头文件
#include <shared_mutex>
#include <nlohmann/json.hpp>  // 引入 JSON 库
#include <stdexcept> // 包含标准异常类// #include <memory>
/* 写json文件 */
using json = nlohmann::json;
namespace fs = std::filesystem;
void writeToJsonFile(const std::string &filename, const json &data, int maxRetries = 3,int retryDelayMilliseconds = 100);
/* 读json文件 */
json readJsonFromFile(const std::string &filename, int maxRetries = 3,int retryDelayMs = 100);class FileLock {
//创建双重锁,文件锁实现进程同步,共享锁实现线程同步,设置为配套获取与释放
private:std::string fileName;int fileDesc;mutable std::shared_mutex rwLock; // 实现线程同步
public:FileLock(const std::string& file) : fileName(file) {// 打开文件(如果文件不存在则创建)fileDesc = open(fileName.c_str(), O_CREAT | O_RDWR, 0666);if (fileDesc == -1) {throw std::runtime_error("Failed to open file for locking: " + fileName);}}~FileLock() {if (fileDesc != -1) {close(fileDesc);  // 关闭文件描述符}}// 禁止复制构造函数和赋值运算符FileLock(const FileLock&) = delete;FileLock& operator=(const FileLock&) = delete;// 锁定文件进行读取void lockRead() {rwLock.lock_shared(); // 获取共享锁(读锁)if (flock(fileDesc, LOCK_SH) == -1) { // 获取共享锁(读锁)// rwLock.unlock_shared(); // 释放共享锁throw std::runtime_error("Failed to lock file for reading: " + fileName);}}// 释放文件读取锁void unlockRead() {if (flock(fileDesc, LOCK_UN) == -1) { // 释放锁throw std::runtime_error("Failed to unlock file after reading: " + fileName);}rwLock.unlock_shared(); // 释放共享锁}// 锁定文件进行写入void lockWrite() {rwLock.lock(); // 获取独占锁(写锁)if (flock(fileDesc, LOCK_EX) == -1) { // 获取独占锁(写锁)// rwLock.unlock(); // 释放独占锁throw std::runtime_error("Failed to lock file for writing: " + fileName);}}// 释放文件写入锁void unlockWrite() {if (flock(fileDesc, LOCK_UN) == -1) { // 释放锁throw std::runtime_error("Failed to unlock file after writing: " + fileName);}rwLock.unlock(); // 释放独占锁}
};class FileManager {
private:// std::unordered_map<std::string, std::shared_ptr<FileLock>> fileLocks;std::unordered_map<std::string, FileLock> fileLocks;std::mutex managerMtx; // 用于保护 fileLocks 的互斥锁// 私有构造函数,禁止外部创建实例FileManager() = default;// 删除拷贝构造函数和赋值运算符FileManager(const FileManager&) = delete;FileManager& operator=(const FileManager&) = delete;public:// 获取单例实例static FileManager& getInstance() {static FileManager instance; // 线程安全的局部静态变量(C++11 及以上)return instance;}// 获取指定文件的锁FileLock& getFileLock(const std::string& fileName) {// std::shared_ptr<FileLock> getFileLock(const std::string& fileName) {std::lock_guard<std::mutex> guard(managerMtx);// // std::cout << "getFileLock:" << fileName << std::endl;// if (fileLocks.find(fileName) == fileLocks.end()) {//     // 如果该文件锁不存在,创建一个新的锁对象//     fileLocks[fileName] = FileLock(fileName); // 永久保存FileLock,减少调用//     // fileLocks[fileName] = std::make_shared<FileLock>(fileName);//动态释放FileLock// }// return fileLocks[fileName];auto it = fileLocks.find(fileName);if (it == fileLocks.end()) {// 如果该文件锁不存在,创建一个新的锁对象并插入到 map 中it = fileLocks.emplace(fileName, fileName).first;}return it->second;}// 移除指定文件的锁(可选)void removeFileLock(const std::string& fileName) {std::lock_guard<std::mutex> guard(managerMtx);fileLocks.erase(fileName);}
};
//创建单例锁管理,永久存储文件锁
FileManager& manager = FileManager::getInstance();//将双重锁 RAII 化, 用于自动管理 FileLock 的写锁
class WriteLockGuard {
public:WriteLockGuard(FileLock& fileLock) : fileLock(fileLock) {fileLock.lockWrite(); // 加锁}~WriteLockGuard() {fileLock.unlockWrite(); // 自动解锁}private:FileLock& fileLock;
};//将双重锁 RAII 化, 用于自动管理 FileLock 的读锁
class ReadLockGuard {
public:ReadLockGuard(FileLock& fileLock) : fileLock(fileLock) {fileLock.lockRead(); // 加锁}~ReadLockGuard() {fileLock.unlockRead(); // 自动解锁}private:FileLock& fileLock;
};/******************************************************************************** 名称: checkJsonFile* 描述: 创建json文件* 作者: mkx* 参数: void* 返回: void******************************************************************************/
void checkJsonFile(const std::string &fileName) {try{// 检查文件是否存在if (fs::exists(fileName)) {return;}// 获取文件所在目录fs::path filePath(fileName);fs::path directory = filePath.parent_path();// std::cout << "filePath:" << filePath << std::endl;// std::cout << "directory:" << directory << std::endl;// 如果目录不存在,则创建目录if (!directory.empty() && !fs::exists(directory)) {// std::cout << "创建目录: " << directory << std::endl;// debug_log(DLOG_INFO, "Directory created: %s", directory.string().c_str());if (!fs::create_directories(directory)) {std::cerr << "无法创建目录: " << directory << std::endl;// debug_log(DLOG_ERROR, "Directory created fail: %s", directory.string().c_str());return;}}FileLock& fileLock = manager.getFileLock(fileName);//以文件名为KEY获取对应锁//WriteLockGuard加锁时会自动创建文件WriteLockGuard lock(fileLock); // 创建 WriteLockGuard 对象,自动加锁if (fs::exists(fileName)) {// debug_log(DLOG_INFO, "File created: %s", filePath.string().c_str());std::cout << "文件创建成功: " << std::endl;return;}}catch (const std::filesystem::filesystem_error &e){const std::string &errorMessage = e.what();// debug_log(DLOG_ERROR, "Error: %s", errorMessage.c_str());}catch (const std::exception &e){const std::string &errorMessage = e.what();// debug_log(DLOG_ERROR, "Error: %s", errorMessage.c_str());}
}/******************************************************************************** 名称: writeToJsonFile* 描述: 写json文件* 作者: mkx* 参数: void* 返回: void******************************************************************************/
void writeToJsonFile(const std::string &filename, const json &data, int maxRetries,int retryDelayMilliseconds)
{checkJsonFile(filename);// 内有双重锁!FileLock& fileLock = manager.getFileLock(filename);//以文件名为KEY获取对应锁for (int retryCount = 0; retryCount < maxRetries; ++retryCount){try{WriteLockGuard lock(fileLock); // 创建 WriteLockGuard 对象,自动加锁std::this_thread::sleep_for(std::chrono::seconds(1));std::ofstream outputFile(filename); //覆盖写入if (outputFile.is_open()) {// 将 JSON 数据写入文件,格式化输出(缩进为4个空格)std::cerr  << data.dump(4) << std::endl;outputFile << data.dump(4) << std::endl; // 换行outputFile.close(); return;}else{throw std::ios_base::failure("Failed to open file for writing.");}}//释放WriteLockGuardcatch (const std::filesystem::filesystem_error &e){const std::string &errorMessage = e.what();// debug_log(DLOG_INFO, "File operation failed: %s", errorMessage.c_str());}catch (const std::ios_base::failure &e){const std::string &errorMessage = e.what();// debug_log(DLOG_INFO, "File operation failed: %s", errorMessage.c_str());}catch (const std::exception &e){const std::string &errorMessage = e.what();// debug_log(DLOG_INFO, "Error: %s", errorMessage.c_str());}// Introduce a delay before retryingstd::this_thread::sleep_for(std::chrono::milliseconds(retryDelayMilliseconds));}// debug_log(DLOG_ERROR, "writeToJsonFile failed, Retry 5 times!!!");
}/******************************************************************************** 名称: readJsonFromFile* 描述: 读取json文件* 作者: mkx* 参数: void* 返回: void******************************************************************************/
json readJsonFromFile(const std::string &filename, int maxRetries, int retryDelayMs)
{checkJsonFile(filename);FileLock& fileLock = manager.getFileLock(filename);//以文件名为KEY获取对应锁for (int attempt = 0; attempt < maxRetries; attempt++){try{ReadLockGuard lock(fileLock); // 创建 ReadLockGuard 对象,自动加锁// std::this_thread::sleep_for(std::chrono::seconds(1));// 打开文件并直接定位到末尾std::ifstream inputFile(filename, std::ios::ate | std::ios::binary); if (inputFile.is_open()){// 检查文件是否为空(避免创建空文件时要写入空json)if (inputFile.tellg() == 0) // 获取文件大小{std::cout << "R" <<  json().dump(4) << std::endl; // 使用 dump(4) 格式化输出,缩进为 4 个空格return json(); // 返回一个空的 JSON 对象}inputFile.seekg(0, std::ios::beg); // 重置文件指针到文件开头json loadedData;inputFile >> loadedData;inputFile.close();loadedData["WR"] = "R";std::cout  << loadedData.dump(4) << std::endl; // 使用 dump(4) 格式化输出,缩进为 4 个空格return loadedData;}else{// debug_log(DLOG_INFO, "File %s not found. ", filename.c_str());std::cout << "else Loaded JSON " << std::endl;}}//释放ReadLockGuardcatch (const std::ios_base::failure &e){const std::string &errorMessage = e.what();// debug_log(DLOG_INFO, "File operation failed: %s", errorMessage.c_str());std::cout << "aaaaaaLoaded JSON " << std::endl;}catch (const std::exception &e){const std::string &errorMessage = e.what();// debug_log(DLOG_INFO, "Error: %s", errorMessage.c_str());std::cout << errorMessage.c_str() << std::endl;}// 重试之前等待一段时间std::this_thread::sleep_for(std::chrono::milliseconds(retryDelayMs));}// debug_log(DLOG_ERROR, "readJsonFromFile failed, Retry 5 times!!!");// 重试次数超过最大限制,返回空的 JSON 对象表示读取失败return json();
}// 使用fork创建进程并执行任务
void createProcess1(const std::string& proID,const std::string& fileName) {pid_t pid = fork();if (pid == 0) {json data = {{"name", fileName},{"age", proID},{"WR", "W"}}; // 在子进程中创建线程进行读写操作std::thread reader1(readJsonFromFile,fileName,1,100);std::thread reader2(readJsonFromFile,fileName,2,100);std::thread writer1(writeToJsonFile,fileName,data,3,100);std::thread writer2(writeToJsonFile,fileName,data,4,100);reader1.join();reader2.join();writer1.join();writer2.join();exit(0); // 退出子进程} else if (pid > 0) {// 父进程wait(NULL); // 等待子进程结束} else {std::cerr << "Fork failed!" << std::endl;}
}int main() {std::string fileName1 = "1.txt";std::string fileName2 = "2.txt";std::string fileName3 = "3.txt";std::string fileName4 = "4.txt";std::string fileName5 = "5.txt";std::string fileName6 = "6.txt";std::string fileName7 = "7.txt";std::string fileName8 = "8.txt";std::string fileName9 = "9.txt";std::string fileName0 = "0.txt";std::string fileNamea = "a.txt";std::string fileNameb = "b.txt";std::string fileNamec = "c.txt";std::string fileNamed = "d.txt";std::string fileNamee = "e.txt";std::string fileNamef = "f.txt";std::string fileNameg = "g.txt";// 创建多个进程进行并行执行std::vector<std::thread> threads;threads.emplace_back(createProcess1,"P1", fileName1);threads.emplace_back(createProcess1,"P2", fileName1);threads.emplace_back(createProcess1,"P3", fileName1);threads.emplace_back(createProcess1,"P4", fileName1);// 等待所有线程完成for (auto& t : threads) {t.join();}return 0;
}

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

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

相关文章

数据分析-使用Excel透视图/表分析禅道数据

背景 禅道&#xff0c;是目前国内用得比较多的研发项目管理系统&#xff0c;我们常常会用它进行需求管理&#xff0c;缺陷跟踪&#xff0c;甚至软件全流程的管理&#xff0c;如果能将平台上的数据结公司的实际情况进行合理的分析利用&#xff0c;相信会给我们的项目复盘总结带来…

精品PPT | AI+智能中台企业架构设计_重新定义制造

这份PPT解决方案的核心内容是介绍了AI智能中台架构设计&#xff0c;旨在通过结合ABC&#xff08;人工智能、大数据、云计算&#xff09;以及IoT技术重新定义制造业。它详细探讨了中台的概念、重要性以及在制造领域的具体应用&#xff0c;展示了如何利用智能中台实现从传统制造到…

语音技术与人工智能:智能语音交互的多场景应用探索

引言 近年来&#xff0c;智能语音技术取得了飞速发展&#xff0c;逐渐渗透到日常生活和各行各业中。从语音助手到智能家居控制&#xff0c;再到企业客服和教育辅导&#xff0c;语音交互正以前所未有的速度改变着人机沟通的方式。这一变革背后&#xff0c;人工智能技术无疑是关键…

瑞芯微 RK 系列 RK3588 使用 ffmpeg-rockchip 实现 MPP 视频硬件编解码-代码版

前言 在上一篇文章中&#xff0c;我们讲解了如何使用 ffmpeg-rockchip 通过命令来实现 MPP 视频硬件编解码和 RGA 硬件图形加速&#xff0c;在这篇文章&#xff0c;我将讲解如何使用 ffmpeg-rockchip 用户空间库&#xff08;代码&#xff09;实现 MPP 硬件编解码。 本文不仅适…

快速、可靠且高性价比的定制IP模式提升芯片设计公司竞争力

作者&#xff1a;Karthik Gopal&#xff0c;SmartDV Technologies亚洲区总经理 智权半导体科技&#xff08;厦门&#xff09;有限公司总经理 无论是在出货量巨大的消费电子市场&#xff0c;还是针对特定应用的细分芯片市场&#xff0c;差异化芯片设计带来的定制化需求也在芯片…

【ARM】MDK如何将变量存储到指定内存地址

1、 文档目标 通过MDK的工程配置&#xff0c;将指定的变量存储到指定的内存地址上。 2、 问题场景 在项目工程的开发过程中&#xff0c;对于flash要进行分区&#xff0c;需要规划出一个特定的内存区域来存储变量。 3、软硬件环境 1&#xff09;、软件版本&#xff1a;MDK 5.…

Mysql--运维篇--空间管理(表空间,索引空间,临时表空间,二进制日志,数据归档等)

MySQL的空间管理是指对数据库存储资源的管理和优化。确保数据库能够高效地使用磁盘空间、内存和其他系统资源。良好的空间管理不仅有助于提高数据库的性能&#xff0c;还能减少存储成本并防止因磁盘空间不足导致的服务中断。MySQL的空间管理涉及多个方面&#xff0c;包括表空间…

Compose 的集成与导航

首先我们来看如何在 View 体系中集成 Compose。 1、迁移策略 Codelab 给出了从 View 迁移到 Compose 的策略&#xff0c;以下内容基本上来自该 Codelab。 Jetpack Compose 从设计之初就考虑到了 View 互操作性。如需迁移到 Compose&#xff0c;我们建议您执行增量迁移&#…

蓝桥杯备考:数据结构之栈 和 stack

目录 栈的概念以及栈的实现 STL 的stack 栈和stack的算法题 栈的模板题 栈的算法题之有效的括号 验证栈序列 后缀表达式 括号匹配 栈的概念以及栈的实现 栈是一种只允许在一端进行插入和删除的线性表 空栈&#xff1a;没有任何元素 入栈&#xff1a;插入元素消息 出…

gesp(C++五级)(1)洛谷:B3941:[GESP样题 五级] 小杨的锻炼

gesp(C五级)&#xff08;1&#xff09;洛谷&#xff1a;B3941&#xff1a;[GESP样题 五级] 小杨的锻炼 题目描述 小杨的班级里共有 n n n 名同学&#xff0c;每位同学都有各自的锻炼习惯。具体来说&#xff0c;第 i i i 位同学每隔 a i a_i ai​ 天就会进行一次锻炼&#x…

MIUI显示/隐藏5G开关的方法,信号弱时开启手机Wifi通话方法

5G网速虽快&#xff0c;手机功耗也大。 1.取消MIUI强制的5G&#xff0c;手动设置4G的方法&#xff01; 【小米澎湃OS, Xiaomi HyperOS显示/隐藏5G开关的方法】 1.1.小米MIUI系统升级后&#xff0c;被强制连5G&#xff0c;手动设置开关被隐藏&#xff0c;如下图&#xff1a; 1…

Gateway 网关

1.Spring Cloud Gateway Spring cloud gateway是spring官方基于Spring 5.0、Spring Boot2.0和Project Reactor等技术开发的网关&#xff0c;Spring Cloud Gateway旨在为微服务架构提供简单、有效和统一的API路由管理方式&#xff0c;Spring Cloud Gateway作为Spring Cloud生态…

python 轮廓 获取环形区域

目录 效果图&#xff1a; 代码&#xff1a; 效果图&#xff1a; 代码&#xff1a; import cv2 import numpy as np# 读取图像 image cv2.imread(rE:\project\jijia\tools_jijia\img_tools\ground_mask.jpg, cv2.IMREAD_GRAYSCALE) # 二值化图像 # 二值化图像 _, binary cv…

MySQL主从复制

文章目录 1.主从复制1.1 概念和原理1.2 案例&#xff1a;一主一从1&#xff09;准备工作2&#xff09;master3&#xff09;slave4&#xff09;测试 1.主从复制 1.1 概念和原理 1.2 案例&#xff1a;一主一从 1&#xff09;准备工作 同步时间 # 安装 ntpdate yum -y install…

网络应用技术 实验七:实现无线局域网

一、实验简介 在 eNSP 中构建无线局域网&#xff0c;并实现全网移动终端互相通信。 二、实验目的 1 、理解无线局域网的工作原理&#xff1b; 2 、熟悉无线局域网的规划与构建过程&#xff1b; 3 、掌握无线局域网的配置方法&#xff1b; 三、实验学时 2 学时 四、实…

51c大模型~合集104

我自己的原文哦~ https://blog.51cto.com/whaosoft/13076849 #Deepfake Detection ACM Computing Surveys | 港大等基于可靠性视角的深度伪造检测综述&#xff0c;覆盖主流基准库、模型 本文作者包括香港大学的王天一、Kam Pui Chow&#xff0c;湖南大学的廖鑫 (共同通讯…

人工智能实验(四)-A*算法求解迷宫寻路问题实验

零、A*算法学习参考资料 1.讲解视频 A*寻路算法详解 #A星 #启发式搜索_哔哩哔哩_bilibili 2.A*算法学习网站 A* 算法简介 一、实验目的 熟悉和掌握A*算法实现迷宫寻路功能&#xff0c;要求掌握启发式函数的编写以及各类启发式函数效果的比较。 二、实验要求 同课本 附录…

Web开发(一)HTML5

Web开发&#xff08;一&#xff09;HTML5 写在前面 参考黑马程序员前端Web教程做的笔记&#xff0c;主要是想后面自己搭建网页玩。 这部分是前端HTML5CSS3移动web视频教程的HTML5部分。主要涉及到HTML的基础语法。 HTML基础 标签定义 HTML定义 HTML(HyperText Markup Lan…

LabVIEW水位监控系统

LabVIEW开发智能水位监控系统通过集成先进的传感技术与控制算法&#xff0c;为工业液体存储提供精确的水位调控&#xff0c;保证了生产过程的连续性与安全性。 项目背景 在化工和饮料生产等行业中&#xff0c;水位控制的准确性对保证生产安全和提高产品质量至关重要。传统的水…

【Rust】结构体定义域实例化

目录 思维导图 1. 结构体的定义与实例化 1.1 结构体的基本概念 1.2 定义结构体 1.3 创建结构体实例 1.4 结构体的定义与实例化示例 2. 访问与修改结构体字段 2.1 访问字段 2.2 修改字段 3. 结构体实例的构造函数 3.1 构造函数的定义 3.2 使用字段初始化简写 4. 结…