Linux下利用文件IO函数完成多进程复制图片,父进程复制前一半,子进程复制后一半

news2024/10/6 23:21:03

Linux下利用文件IO函数完成多进程复制图片,父进程复制前一半,子进程复制后一半

一 、概述

  • 在Linux环境下,利用多进程完成图片的复制操作
  • 本demo用到了两个进程,一个是主函数所在的父进程,一个在主函数里面创建的子进程
  • 父进程负责复制图片的前一半,子进程复制图片的后一半

1.1 思路

  • 最开始我想到的是一个字节一个字节复制,等复制完前一半的内容后再创建子进程,然后子进程负责后面的复制,

  • 写完后进行了改进,在父进程里面创建一个buff(char buff[128]),然后每次复制时判断是否复制到了一半,这样的效率比一个字节复制要快

  • 后来又想到了,既然是多进程,那么最好上来就创建子进程来练习,不然多进程就没有了意义

    • 而这种上来就创建子进程,后面发现还是需要父进程先完成复制,再让子进程进行复制,否则会出现对文件操作的光标紊乱
    • 假设:父的光标到了5,切换到子进程,子进程追加复制了20字节,当前子进程的光标就保留在了25的位置,切回到父进程,父进程从5后面开始继续复制,假设复制了30字节,再切到子进程的时候,子进程光标还处于25的位置,因此会出现光标位置错乱
  • 由于会出现光标错乱的问题,然后想到了通过 lseek 函数 调整光标到最后,发现还是不可以,因为我用的是两个文件描述符表,而且指向的系统文件表也不是一个位置

  • 目前的想法是,如同 CPU 在终端、异常、系统调用时保留断点一样,父子进程每次复制完分别更新自己的断点,下一次更换进程后再回来时也能读取到这个断点

  • 目前的难点在于:每次复制的操作并不是一个原子操作,如何能够确保每次复制时都能够完完整整的执行完一次复制操作后再切换进程

  • 由于文件 IO 函数 lseek 在文件的尾部向后继续偏移会补充0,且这些0在填充到此位置时会变成填充的数据,那么可以直接先想复制后的文件向后偏移被复制的文件的一般字节数,然后直接向后填充,那么就可以做到多进程同时运行填充

1.2 文件分布

  • 只有一个代码文件,且功能都写在了主函数中
  • 一个已经存在的图片文件,是被复制的对象
  • 一个准备创建的图片文件,是复制完成后的对象

1.3 运行环境

  • 直接gcc编译即可

1.4 运行环境

  • 本代码是在Linux----ubuntu18.04中运行的,
  • 如果报错之类的,可以检查一下是不是环境不同导致

二、上代码

picture_copy.c

#include <my_head.h>

//  图片拷贝,父进程拷贝前半部分,子进程拷贝后半部分
int main(int argc, const char *argv[])
{
    //  清空图片
    int dest = open("2.png", O_RDWR | O_CREAT | O_TRUNC, 0664);
    close(dest);

    //  打开俩文件
    int src1 = open("1.png", O_RDONLY);
    int dest1 = open("2.png", O_RDWR | O_CREAT, 0664);
    //  获取src的文件大小
    off_t size = lseek(src1, 0, SEEK_END);
    lseek(src1, 0, SEEK_SET);
    //  获取src的一半偏移量
    off_t offset = size / 2;

    ssize_t res = 0;
    int wstatus;
    //  创建子进程
    int cpid = fork();
    if (0 < cpid)
    {
        //  父进程
#if 1
        //  父进程拷贝,从头开始拷贝前一半,放到头部
        char buff[128];

        while (offset >= 0)
        {
            bzero(buff, sizeof(buff));
            //  这个地方不能用 (offset - sizeof(buff) ) >= 0 判断,
            //  因为offset是有符号数,sizeof(buff)是无符号数
            //  有符号数和无符号数运算,会转换成无符号数
            if (offset >= sizeof(buff))
            {
                /*
                    如果前半部分剩余的比设定的缓冲区大
                    直接读取,读写完再改变剩余的计数量
                */
                res = read(src1, &buff, sizeof(buff));
                if (res > 0)
                {
                    write(dest1, &buff, res);
                }
                else
                {
                    if (res == -1)
                    {
                        ERR_MSG("read");
                    }

                    break;
                }
            }
            else
            {
                /*
                    如果前半部分剩余的比设定的缓冲区小或者相等
                    读取剩余的量
                    要注意,这个地方只需要读一次,因为到中间了
                */
                // printf("offset = %ld\n", offset);
                res = read(src1, &buff, offset);
                write(dest1, &buff, res);
            }
            //  更新offset
            offset -= sizeof(buff);
        }
        wait(&wstatus);
        if (WEXITSTATUS(wstatus) == 1)
        {
            close(src1);
            close(dest1);
        }

#endif
    }
    else if (0 == cpid)
    {
#if 1
        // 子进程拷贝,从中间向后拷贝
        int src2 = open("1.png", O_RDONLY);
        int dest2 = open("2.png", O_RDWR | O_CREAT, 0664);
        // printf("offset ==== %ld\n", offset);
        lseek(src2, offset, SEEK_SET);
        lseek(dest2, offset, SEEK_SET);
        char buff[128];
        while (1)
        {
            bzero(buff, sizeof(buff));
            res = read(src2, buff, sizeof(buff));
            if (res > 0)
            {
                write(dest2, buff, res);
            }
            else
                break;
        }
#endif

        exit(1);
    }
    else
    {
        ERR_MSG("fork");
    }

    return 0;
}

运行结果

在这里插入图片描述

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

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

相关文章

安装系统作为启动盘的U盘恢复原样

1、插U盘 2、winr——cmd&#xff0c;输入diskpart 3、此电脑——管理——磁盘管理——查看磁盘号&#xff1a;磁盘 1 4、输入&#xff1a;select disk 1——clean 5、磁盘管理——右击新建简单卷——下一步即可

u盘传输数据的时候拔出会怎么样?小心这些危害

U盘是我们日常生活和工作中常使用的一种便携式存储设备。然而&#xff0c;在使用U盘传输数据时&#xff0c;有时我们会不小心将它拔出&#xff0c;而这个看似微不足道的行为实际上可能会带来严重的后果。本文将向您介绍U盘在传输数据时突然拔出可能导致的各种危害&#xff0c;其…

如何恢复U盘里面的已经损坏的数据?

弹出使用驱动器之前&#xff0c;先将U盘格式化的信息框&#xff0c;是Windows系统针对某些特定类型的U盘或移动硬盘的一种常见处理方式。一般来说&#xff0c;如果U盘或移动硬盘出现某些故障或问题&#xff0c;Windows系统会建议用户将其格式化。 格式化是一种常规的操作&…

Kafka消费者组重平衡(二)

文章目录 概要重平衡通知机制消费组组状态消费端重平衡流程Broker端重平衡流程 概要 上一篇Kafka消费者组重平衡主要介绍了重平衡相关的概念&#xff0c;本篇主要梳理重平衡发生的流程。 为了更好地观察&#xff0c;数据准备如下&#xff1a; kafka版本&#xff1a;kafka_2.1…

9.12 C++作业

实现一个图形类&#xff08;Shape&#xff09;&#xff0c;包含受保护成员属性&#xff1a;周长、面积&#xff0c; 公共成员函数&#xff1a;特殊成员函数书写 定义一个圆形类&#xff08;Circle&#xff09;&#xff0c;继承自图形类&#xff0c;包含私有属性&#xff1a;半…

模拟信号电压或电流信号转变频器频率传感器信号隔离变送器0-5V/0-10V/0-20mA/4-20mA转0-5KHz/0-10KHz/1-5KHz

主要特性: 精度等级&#xff1a;0.1 级、0.2 级。产品出厂前已检验校正&#xff0c;用户可以直接使用输 入 &#xff1a;0-5V/0-10V/1-5V,0-10mA/0-20mA/4-20mA 等输出信号&#xff1a;0-5KHz/0-10KHz/1-5KHz 等标准信号辅助电源&#xff1a;5V、9V、12V、15V 或 24V 直流单电…

OpenCV(四十三):Shi-Tomas角点检测

1.Shi-Tomas角点检测原理 Shi-Tomasi&#xff08;也称为Good Features to Track&#xff09;角点检测算法是一种改进的角点检测方法&#xff0c;它基于Harris角点检测算法&#xff0c;并针对一些不足进行了改进。 与Harris角点检测不同&#xff0c;Shi-Tomasi使用了更简化的角点…

PDF怎么合并?这几个方法收藏起来吧

PDF文件是一种非常常见的文档格式&#xff0c;它具有跨平台、易于阅读和打印等优点&#xff0c;因此在生活和工作中得到了广泛的应用。当我们需要将多个PDF文件合并成一个文件时&#xff0c;我们可以采用以下几种方法。 方法一&#xff1a;使用PDF转换工具 我们在电脑上打开迅…

Spring Boot 中的 @CacheEvict 注解使用

Spring Boot 中的 CacheEvict 注解 在 Spring Boot 中&#xff0c;缓存是提高应用性能的重要手段。为了更好地管理缓存&#xff0c;Spring Boot 提供了一系列的缓存注解&#xff0c;其中 CacheEvict 注解用于清空缓存。 本文将介绍 CacheEvict 注解的含义、原理以及如何使用。…

华为云云耀云服务器L实例评测-基于华为云服务器的测试及简单配置

引言 云计算已经成为现代企业和个人的重要组成部分。在云计算市场上&#xff0c;华为云一直以来都以其出色的性能和服务质量而闻名。周末的时候&#xff0c;利用华为云云耀云服务器搭建了一个基于hexo的个人博客&#xff0c;我用的是2核2G的3M带宽的配置&#xff0c;访问起来挺…

自动化搭建(Jenkins_Docker)1

简介 目前为了搭建Android自动化构建&#xff0c; 包含自动打包、代码审查工具以及自动化测试的串联。如下图&#xff1a; 我拿到的是一个2T的一个服务器&#xff0c;需要在上面搭建整个环境&#xff0c; 整体分解如下&#xff1a; Java安装Jenkins安装和配置Gerrit 和 rep…

GIS前端—地图标注

GIS前端—地图标注 地图标注原理图片标注文本标注矢量图形标注 地图标注原理 地图标注是将空间位置信息点与地图关联&#xff0c;通过图标、窗口等形式把点相关的信息展现在地图上。地图标注是WebGIS应用的核心功能之一&#xff0c;在大众应用中十分常见。基于地图标注可以为用…

使用代码产生标准的软件架构图之C4

在软件开发的流程中&#xff0c; 软件架构图是重要的软件文档&#xff0c;软件架构图包含有多个层级&#xff0c;最常见的&#xff0c;有软件的整体架构和组件、类等图。 整体架构可能使用PPT或者一些绘图工具Visio来绘制组件、类等图有UML的标准&#xff0c; 也可以使用Visio…

【Android知识笔记】进程通信(二)

一、Binder对象是如何跨进程传递的 binder传递有哪些方式?binder在传递过程中是怎么存储的?binder对象序列化和反序列化过程?binder对象传递过程中驱动层做了什么?总结 Binder 对象的跨进程传递主要靠 Parcel 的两个关键方法 writeStrongBinder() 和

【数据结构】—堆排序以及TOP-K问题究极详解(含C语言实现)

食用指南&#xff1a;本文在有C基础的情况下食用更佳 &#x1f525;这就不得不推荐此专栏了&#xff1a;C语言 ♈️今日夜电波&#xff1a;ルミネセンス—今泉愛夏 1:01 ━━━━━━️&#x1f49f;──────── 5:05 …

[刷题记录]牛客面试笔刷TOP101(一)

牛客笔试算法必刷TOP101系列,每日更新中~(主要是记录自己的刷题,所以描述的可能不是很清楚 但如果刚好能帮助到你就更好了) 后续后头复习的时候,记得是看正解啊,别对着错的例子傻傻看了... 目录 1.合并有序链表2023.9.3 2.链表是否有环2023.9.4 3.判断链表中环的入口点 …

学Python的漫画漫步进阶 -- 第三步

学Python的漫画漫步进阶 -- 第三步 三、数字类型的数据3.1 Python中的数据类型3.2 整数类型3.3 浮点类型3.4 复数类型3.5 布尔类型3.6 数字类型的相互转换3.6.1 隐式类型的转换3.6.2 显式类型的转换 3.7 练一练3.8 数字类型的总结全部16步完成后 &#xff0c;后续就是介绍项目实…

走进甄云,探寻SRM独角兽成功背后的故事

随着科技的快速发展和全球商业环境的不断变化&#xff0c;中国企业对灵活性、创新性、全球化和效率的需求是迫切的&#xff0c;数字化转型已经成为企业生存和发展的关键因素&#xff0c;对企业具有重要意义&#xff0c;是组织生存和发展的必然趋势。数字化转型涉及整个组织、多…

PMP-项目规划过程组的重要性

一、什么是项目规划过程组 规划过程组包括明确项目全部范围、定义和优化目标&#xff0c;并为实现目标制定行动方案的一组过程。规划过程组中的过程制定项目管理计划的组成部分&#xff0c;以及用于执行项目的项目文件。取决于项目本身的性质&#xff0c;可能需要通过多轮反馈来…

片上网络(1)概述

前言 NoC&#xff1a;On-Chip Networks&#xff0c;片上网络。 由于多核乃至众核时代的到来&#xff0c;用于连接它们的可扩展、低延迟、大带宽的通信结构变得至关重要。 在核心较少时&#xff0c;总线Bus和矩阵/交叉开关Crossbar是主要的互联结构。总线可以提供较低的传输延迟…