跟我学c++中级篇——多线程中的文件处理

一、文件处理

作为IO处理的一种重要场景,文件处理是几乎所有编程都无法绕过的一个情况。稍微复杂的一些的程序都可能需要文件处理,不管这种文件处理对开发者来说是显式的还是隐式的。相对于其它语言,C++并未提供多么好的文件处理API接口,即使发展到现在,C++新标准的文件处理,相比与C#等语言处理起文件的方式仍然要落后不少。
文件处理相对来说的复杂再加上C++中线程管理的复杂,二者结合到一起,就会产生各种大大小小的问题。

二、多线程与资源控制

其实对开发者来说,不管是文件管理还是其它资源管理,最主要的就是在多线程的切换中,保持安全性(不能崩溃)、数据的准确性(不能写得不对)。在这些基础上,如何提高资源处理的速度并按照开发者既定的意愿去完成相关的资源控制,这才是难点所在。
特别在一些具体的场景中,如大文件(海量日志文件)、数据库操作以及图像视频等的处理,这都需要多线程参与下的高效率的处理。在前面学习多线程时知道对资源的控制一般有几种处理方法:
1、使用锁
这里的锁,包括各种的互斥体和信号量等
2、使用原子变量
其实,使用原子变量的目的也类似于锁
3、使用无锁编程
这个就相对复杂很多,而且适用场景也受限

三、多线程条件下的文件处理方法

上面的这些方法对于所有的资源控制都是行之有效的,但针对文件处理,可能一些更具体的方法。对于文件来说,需要处理两种情况即:
1、文件的写
文件的写是一种常见的保存数据的方法,数据库的写其实也一种文件的写,只不过,上面又抽象了一层数据库的相关操作。对于写文件来说,最基础的是写入的完整性、一致性,最重要的是写入的速度。
多线程的写入,往往因为同步的问题,引起以下的情况:
a)由于无法同步导致的问题
包括数据写入顺序不一致引起的数据覆盖以及数据顺序的不正确,导致数据的完整性的缺损,从而最终导致文件可能无法打开
b)因为同步导致写入效率的问题
多线程的情况下,不适当的同步,或者说即使是适当的同步,也会大幅的降低写文件的速度
c)引入异步IO导致的编程复杂性
异步IO的操作本身就是一个难点,这对于很多开发者说,掌握的都不是很到位
d)是否使用写缓冲
其实在很多情况,特别是在多线程的情况下,往往会把并发写转成串行写,数据量的增加往往要求引入缓冲区
总之,写文件,是多线程操作中相对复杂和困难的情况。
写文件有几种情况比较特殊,一种是写入大量的小文件,这种情况在互联网中特别常见,比如大量的商品的缩略图;另外一种是写一个非常大的文件,如日志;另外还有大家常见的如BT等下载软件,多线程分段下载然后最终再组成一个大文件(分块处理)。

2、文件的读
文件的读相对写来说应用场景更丰富,在互联网中针对文件读还专门有各种的优化方法。比如各种缓冲、临时文件等等。
多线程情况下的文件读其实有很多种方法,来适应不同的场景:
a)使用缓冲
这种缓冲既包括硬件本身的缓冲也包括软件层次的缓冲,甚至是框架之间的缓冲,如使用内存型数据库(如Redis)+传统的数据库(如MySql),前者就可以作为后者的缓冲。而在C++编程中也提供了iosteam的缓冲的控制。其它的一些系统API和库的API也多少都提供了类似的功能。
b)使用异步IO
异步IO的问题主要就在于异步编程的复杂度,这里不再赘述
c)多线程读取的时效问题
也就是常见的读写同时在进行时,如何保证读的时效性(即尽可能减少脏读),特别是在分布式、多线程的情况下。

四、典型的文件处理方式

内存缓冲区 使用新的异步框架 或新技术
典型的文件处理方式一般有以下几种处理方法:
1、使用内存映射
这个在操作一些大的日志文件时,经常使用这种内存映射,从而快速读写日志。
2、使用缓冲
包括前面提到的软件层次的缓冲、硬件缓冲及内核缓冲等。
3、使用最新的框架或技术
比如前文“Linux新的IO模型io_uring”提到的io_uring以及其它的新技术、新框架甚至是新思想,来解决某些对文件操作极度严苛的场景。
4、使用合理的策略
这个就比较灵活了,比如上面提到的大文件的多线程下载,就可以使用合理的策略来进行分块然后再进行传输、验证、组合等等。另外在数据库读写中,面对大量的写可以使用批处理,而使用缓冲时,可以在大多数场景下指定临界值再进行真正的写入等等。
5、多线程的合理控制
无论何种情况,只要发生在了多线程并发或并行的场景下,合理调试线程和分配任务就是一种高优先级的考虑方向了。也可以这样认为,面对复杂的文件处理,不是某一层可以解决的,它是从上到下,从里到外,一个综合应用的场景。

五、实际的例子

下面级出一个大日志文件使用内存映射操作的例程:

#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <system_error>class MemMappedFile {
public:explicit MemMappedFile(const std::string& path, bool enable = false) {// 打开文件int flags = enable ? O_RDWR : O_RDONLY;m_fd = open(path.c_str(), flags);if (m_fd == -1) {return;}// 获取映射文件大小struct stat sb;if (fstat(m_fd, &sb) == -1) {close(m_fd);return ;}m_size = sb.st_size;// 创建内存映射int prot = PROT_READ | (enable ? PROT_WRITE : 0);m_data = mmap(nullptr, m_size, prot, MAP_SHARED, m_fd, 0);if (m_data == MAP_FAILED) {close(m_fd);return;}}~MemMappedFile() {if (m_data != nullptr) {munmap(m_data, m_size);}if (m_fd != -1) {close(m_fd);}}MemMappedFile(const MemMappedFile&) = delete;MemMappedFile& operator=(const MemMappedFile&) = delete;
public:char* data() const { return static_cast<char*>(m_data); }size_t size() const { return m_size; }// 同步修改到磁盘void syncToDisk() {if (msync(m_data, m_size, MS_SYNC) == -1) {return;}}private:int m_fd = -1;void* m_data = nullptr;size_t m_size = 0;
};
// 处理数据
void processData(const char* chunk, size_t  size) {// 日志处理,略过
}
int main(int argc, char* argv[]) {if (argc < 2) {std::cerr << "cur use: " << argv[0] << std::endl;return 1;}try {//创建映射bool enable = (argc >= 3);MemMappedFile mmapFile(argv[1], enable);const char* data = mmapFile.data();size_t size = mmapFile.size();size_t lineCount = 0;size_t errNum = 0;const char* keyword = "ERR";for (size_t i = 0; i < size; ++i) {if (data[i] == '\n') {lineCount++;}if (strncmp(&data[i], keyword, strlen(keyword)) == 0) {errNum++;i += strlen(keyword) - 1;}}std::cout << "lines is: " << lineCount<< "errors is: " << errNum  << std::endl;if (enable) {const char* newHeader = "start modify log...\n";size_t headerLen = strlen(newHeader);if (size >= headerLen) {memcpy(mmapFile.data(), newHeader, headerLen);mmapFile.syncToDisk();}}//分块处理const size_t chunkSize = 1024 * 1024;for (size_t offset = 0; offset < size; offset += chunkSize) {size_t chunkLen = std::min(chunkSize, size - offset);processData(data + offset, chunkLen);}} catch (const std::exception& e) {std::cerr << "Error: " << e.what() << std::endl;return 1;}return 0;
}

注释已经很清晰,大家可以参考一下。

六、总结

多线程下的文件处理,需要整合前面学习的很多知识点。大家不用把它想象的多么难,重点在于分析实际的应用场景,找出一个合适的解决方案就可以了。不是每个开发者都会遇到海量的数据读写。但掌握一些海量数据下的文件处理的经验却是非常必要的。

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

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

相关文章

Flutter知识点汇总

Flutter架构解析 1. Flutter 是什么?它与其他移动开发框架有什么不同? Flutter 是 Google 开发的开源移动应用开发框架,可用于快速构建高性能、高保真的移动应用(iOS 和 Android),也支持 Web、桌面和嵌入式设备。。它与其他移动开发框架(如 React Native、Xamarin、原…

【会员专享数据】1980—2022年中国逐日月年潜在蒸散发栅格数据

气象数据是我们在各项研究中都经常使用的数据&#xff0c;尤其是高精度的气象数据应用价值非常高。 之前我们分享过研究者张凌, 胡英屹等发布在国家冰川冻土沙漠科学数据中心平台上的nc格式的1980—2022年中国高分辨率逐日、逐月、逐年气象数据&#xff01;很多小伙伴拿到数据…

前端打包工具简单介绍

前端打包工具简单介绍 一、Webpack 架构与插件机制 1. Webpack 架构核心组成 Entry&#xff08;入口&#xff09; 指定应用的起点文件&#xff0c;比如 src/index.js。 Module&#xff08;模块&#xff09; Webpack 把项目当作模块图&#xff0c;模块可以是 JS、CSS、图片等…

工业控制核心引擎高性能MCU——MM32F5370

RAMSUN提供的MM32F5370搭载180MHz Arm China Star-MC1处理器&#xff0c;集成DSP、FPU与三角函数加速单元&#xff08;CORDIC&#xff09;&#xff0c;轻松应对复杂算法需求。其技术亮点包括&#xff1a; 超高精度PWM&#xff1a;8通道208ps级高精度PWM输出&#xff0c;满足储能…

AI架构师修炼之道

1 AI时代的架构革命 与传统软件开发和软件架构师相比&#xff0c;AI架构师面临着三重范式转换&#xff1a; 1.1 技术维度&#xff0c;需处理异构算力调度与模型生命周期管理的复杂性&#xff1b; 1.2 系统维度&#xff0c;需平衡实时性与资源约束的矛盾&#xff1b; 1.3 价…

数学建模期末速成 主成分分析的基本步骤

设有 n n n个研究对象&#xff0c; m m m个指标变量 x 1 , x 2 , ⋯ , x m x_1,x_2,\cdots,x_m x1​,x2​,⋯,xm​&#xff0c;第 i i i个对象关于第 j j j个指标取值为 a i j a_{ij} aij​,构造数据矩阵 A ( a i j ) n m A\left(\begin{array}{c}a_{ij}\end{array}\right)_{…

博图 SCL 编程技巧:灵活实现上升沿与下降沿检测案例分享(上)

博图 SCL 编程技巧&#xff1a;灵活实现上升沿与下降沿检测案例分享 在 PLC 编程中&#xff0c;检测信号从 0 变为 1 (上升沿) 或从 1 变为 0 (下降沿) 是最基础也是最关键的操作之一。它常用于启动单次动作、计数、状态切换等场景。在西门子 TIA Portal 环境中&#xff0c;虽…

深度学习入门Day3--鱼书学习(2)

这俩天刚忙完答辩的事情&#xff0c;终于有时间学习了 一、3层神经网络实现 1.本节中的符号使用说明。 w 12 ( 1 ) w_{12}^{(1)} w12(1)​表示前一层的第2个神经元 x 2 x_{2} x2​到后一层的第一个神经元 a 1 a_{1} a1​的权重。权重右下角按照“后一层的索引号、前一层的索引…

服务器 | Centos 9 系统中,如何部署SpringBoot后端项目?

系列文章目录 虚拟机 | Ubuntu 安装流程以及界面太小问题解决 虚拟机 | Ubuntu图形化系统&#xff1a; open-vm-tools安装失败以及实现文件拖放 虚拟机 | Ubuntu操作系统&#xff1a;su和sudo理解及如何处理忘记root密码 文章目录 系列文章目录前言一、环境介绍二、 使用syst…

CNN核心机制深度解析:卷积池化原理 PyTorch实现经典网络

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文系统讲解CNN核心原理、经典网络架构和图像分类实战&#xff0c;涵盖卷积层、池化层、LeNet/AlexNet/VGG/ResNet设计思想&#xff0c;并提供CIFAR-…

6个月Python学习计划 Day 17 - 继承、多态与魔术方法

第三周 Day 4 &#x1f3af; 今日目标 理解类的继承和方法重写掌握多态思想及其实际应用了解并使用常见的魔术方法&#xff08;如 str、len 等&#xff09; &#x1f9ec; 类的继承&#xff08;Inheritance&#xff09; Python 支持单继承与多继承&#xff0c;常用语法如下&…

抖音怎么下载视频

抖音作为一款短视频社交平台&#xff0c;凭借其独特的短视频形式和丰富的内容&#xff0c;吸引了大量用户。有些用户在欣赏完抖音视频后&#xff0c;想要将其保存下来&#xff0c;以便日后观看。如何在抖音下载视频呢&#xff1f;本文将为您详细介绍抖音视频下载的技巧和方法。…

使用MinIO搭建自己的分布式文件存储

目录 引言&#xff1a; 一.什么是 MinIO &#xff1f; 二.MinIO 的安装与部署&#xff1a; 三.Spring Cloud 集成 MinIO&#xff1a; 1.前提准备&#xff1a; &#xff08;1&#xff09;安装依赖&#xff1a; &#xff08;2&#xff09;配置MinIO连接&#xff1a; &…

uni-app 如何实现选择和上传非图像、视频文件?

在 uni-app 中实现选择和上传非图像、视频文件&#xff0c;可根据不同端&#xff08;App、H5、小程序&#xff09;的特点&#xff0c;采用以下方法&#xff1a; 一、通用思路&#xff08;多端适配优先推荐&#xff09; 借助 uni.chooseFile 选择文件&#xff0c;再用 uni.upl…

正点原子[第三期]Arm(iMX6U)Linux移植学习笔记-12.1 Linux内核启动流程简介

前言&#xff1a; 本文是根据哔哩哔哩网站上“Arm(iMX6U)Linux系统移植和根文件系统构键篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。 引用&#xff1a; …

UDP与TCP通信协议技术解析

文章目录 协议基础原理TCP&#xff1a;可靠的面向连接通信UDP&#xff1a;高效的无连接通信 性能特征分析TCP性能表现UDP性能表现 应用场景分析TCP适用场景UDP适用场景 技术实现考量错误处理策略网络资源利用 选择决策框架可靠性需求评估性能要求分析 混合方案设计协议组合策略…

mysql 页的理解和实际分析

目录 页&#xff08;Page&#xff09;是 Innodb 存储引擎用于管理数据的最小磁盘单位B树的一般高度记录在页中的存储 innodb ibd文件innodb 页类型分析ibd文件查看数据表的行格式查看ibd文件 分析 ibd的第4个页&#xff1a;B-tree Node类型先分析File Header(38字节-描述页信息…

【优选算法】C++滑动窗口

1、长度最小的子数组 思路&#xff1a; class Solution { public:int minSubArrayLen(int target, vector<int>& nums) {// 滑动窗口// 1.left0,right0// 2.进窗口( nums[right])// 3.判断// 出窗口// (4.更新结果)// 总和大于等于 target 的长度最小的 子数组…

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…

408考研逐题详解:2009年第33题

2009年第33题 在 OSI 参考模型中&#xff0c;自下而上第一个提供端到端服务的层次是&#xff08; &#xff09; A. 数据链路层 \qquad B. 传输层 \qquad C. 会话层 \qquad D.应用层 解析 本题主要考查 OSI 参考模型各层的核心功能、端到端服务的定义。 OSI 参考模型&am…