【操作系统】多进程拷贝|进程重载

🔥 博客主页我要成为C++领域大神
🎥 系列专栏【C++核心编程】 【计算机网络】 【Linux编程】 【操作系统】

❤️感谢大家点赞👍收藏⭐评论✍️

本博客致力于分享知识,欢迎大家共同学习和交流。

为什么要进行多进程拷贝?

这涉及到了分时复用原理

分时复用原理

分时复用:在多进程环境下,进程在时间片内与CPU进行交互,时间片用完时进程会被中断,等待下一次CPU使用权限。

时间片:每个进程在运行时会被分配一个时间片,时间片用完后CPU会切换到另一个进程。

多进程拷贝优势:通过多进程处理,可以更高效地利用系统资源(CPU、内存),减少大文件拷贝任务的完成时间。

执行方式对比

串行执行:任务严格按顺序执行,从头到尾依次处理。

优点:简单、易实现。

缺点:不能充分利用系统资源,效率低。

并发执行:多个任务在同一时间段内执行,但不一定同时进行,利用CPU切换完成多个任务。

优点:比串行执行更高效,能更好地利用CPU。

缺点:需要处理进程间的通信和同步问题。

并行执行:物理上同时进行,多个核心或处理器同时执行多个任务。

优点:最高效的执行方式,可以显著缩短任务完成时间。

缺点:需要多核或多处理器支持,复杂度更高。

不要频繁的进程切换,频繁切换会浪费开销,影响系统性能。

多进程可以加快任务完成速度,但需要合理的任务分配和资源管理。

多进程拷贝的优点

1. 提高文件拷贝效率

并行处理:多进程拷贝通过并行处理文件的不同部分,可以显著提高拷贝速度,尤其是对于大文件而言。

减少I/O等待时间:多个进程可以同时进行读取和写入操作,减少了单个进程的I/O等待时间,提高整体效率。

2. 充分利用系统资源

多核CPU的利用:现代计算机通常配备多核CPU,多进程拷贝可以同时利用多个CPU核心,避免资源闲置。

内存利用:多进程可以更好地利用系统内存和缓存,提高数据处理效率。

3. 提高系统响应性

负载分散:通过将文件拷贝任务分散到多个进程,可以减小单个进程的负载,使系统在执行大文件拷贝时仍能保持较好的响应性。

任务中断与恢复:多进程模式下,如果某个进程失败,只需重新启动该进程或重新分配任务,而不必重新开始整个文件拷贝,提高了拷贝任务的健壮性。

应用场景

在需要拷贝超大文件时,单进程的处理速度较慢,而多进程可以显著加快拷贝速度。

在需要同时执行多个文件拷贝任务的场景,多进程可以同时处理多个任务,提高整体处理效率。

多进程拷贝的流程

Process_Copy.c

命令行参数Process_Copy 的输入包括源文件路径、目标文件路径、进程数量(可选,默认为5)。

参数校验:程序首先会检查参数数量和文件路径的有效性。

任务量计算:通过计算源文件大小和进程数量来确定每个进程处理的字节数,处理任务被分成多块。

多进程创建 :根据用户指定的进程数量,创建多个子进程(cp_process)。

文件分块:源文件、目标文件、任务量和进程数被传递给每个子进程,子进程负责处理指定块的文件拷贝。

进程重载 :对每个子进程使用execl函数进行重载,让其实现copy.c的功能。

关于execl函数的使用,可以看我这期博客【Linux】execl函数详解|进程重载

Copy.c

任务接收与处理:接收任务并进行位置转换,以便正确处理文件偏移量。

文件操作

打开文件:以读方式打开源文件,以写方式打开目标文件。

文件指针调整:将源文件和目标文件的指针移动到指定位置,确保正确的读取和写入。

读写操作:读取源文件的数据并写入到目标文件中。

关闭文件:完成操作后,关闭文件描述符并退出进程。

流程

执行 Process_Copy ,传入源文件路径、目标文件路径,多线程数量。

Process_Copy 计算每个进程的任务量,创建并分配子进程。

每个子进程通过 Copy 执行文件拷贝任务,处理源文件和目标文件的读写操作。

  1. 参数校验 -> 任务量计算 -> 进程创建 -> 子进程执行文件拷贝。
  2. 子进程根据任务量和位置执行读写操作,直到完成整个文件的拷贝。

代码实现

Process_Copy.c

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/fcntl.h>
#include <sys/wait.h> 

/* 多进程拷贝样例 */
int Block_Cur(const char* File_Name,int Pro_Number)
{
    /* 计算每个进程应该拷贝的大小 */
    int fd;
    if((fd=open(File_Name,O_RDONLY))==-1){
        perror("Block_Cur>>file open fail");
        exit(0);
    }
    int fsize;
    if((fsize=lseek(fd,0,SEEK_END))==-1){
        perror("Block_Cur>>get filesize fail");
        exit(0);
    }
    if(fsize%Pro_Number==0)
        return fsize/Pro_Number;
    else 
        return fsize/Pro_Number+1;

}

/* Process_Copy SRC DES 30,进程数量可缺省 */
int Check_Pram(int Arg_No,const char* Src_File,int Pro_Number)
{
    if(Arg_No<3){
        printf("Error:Pram Error\n");
        exit(0);
    }

    if(access(Src_File,F_OK)!=0){
        printf("Error:Src_File Not Exist\n");
        exit(0);
    }

    if(Pro_Number<=0 || Pro_Number>80){
        printf("Error:Pro_Number is Limited\n");
        exit(0);
    }

    return 0;
}

int Process_Create(const char* Src_File,const char *Des_File,int Pro_Number,int Blocksize)
{
    pid_t pid;
    int i;
    /* 循环创建空格 */
    for(i=0;i<Pro_Number;++i){
        pid=fork();
        if(pid==0) break;
    }
    if(pid>0){/* 父进程工作区 */
       printf("Parent Process PID:%d wait...\n",getpid());
        /* 回收僵尸进程 */
        pid_t zpid;
        while((zpid=wait(NULL))>0){
            printf("wait sucess,ZPID:%d\n",zpid);
        }
    }else if(pid==0){/* 子进程工作区 */
        int pos=0;
        pos=i*Blocksize;
        char str_Blocksize[10];
        char str_pos[10];
        bzero(str_Blocksize,10);
        bzero(str_pos,10);
        sprintf(str_Blocksize,"%d",Blocksize);
        sprintf(str_pos,"%d",pos);
        execl("/home/cppstudy/code/PROCESS/Process_Copy/copy","copy",Src_File,Des_File,str_Blocksize,str_pos,NULL);
        
    }else{
        perror("fork call failed");
        exit(0);
    }
}
int main(int argc,char** argv)
{      int Pro_Number=0;
       if(argv[3]==0) Pro_Number=5;
       else Pro_Number=atoi(argv[3]);
       /* 参数校验 */
       Check_Pram(argc,argv[1],Pro_Number);
       /* 任务量分割 */
       int Block_Size=Block_Cur(argv[1],Pro_Number);
       /* 进程创建 */
       Process_Create(argv[1],argv[2],Pro_Number,Block_Size);
		return 0;
}

Copy.c

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/fcntl.h>
 

int main(int argc,char**argv)
{
    int blocksize;
    int pos;
    ssize_t len;
    int sfd;
    int dfd;
    blocksize=atoi(argv[3]);
    pos=atoi(argv[4]);
    char buffer[blocksize];
    bzero(buffer,sizeof(buffer));
    printf("Child Process PID:%d copy sucess,File_Name:%s,Blocksize:%d,pos:%d\n",getpid(),argv[1],blocksize,pos);
    if((sfd=open(argv[1],O_RDONLY))==-1){
            printf("%s open fail\n",argv[1]);
            exit(0);
    }
    if((dfd=open(argv[2],O_RDWR|O_CREAT,0664))==-1)
    {
            printf("%s create fail\n",argv[2]);
            exit(0);
    }
    
    /* 读写指针偏移位置 */
    lseek(sfd,pos,SEEK_SET);
    lseek(dfd,pos,SEEK_SET);
    len=read(sfd,buffer,sizeof(buffer));
    write(dfd,buffer,len);
    close(sfd);
    close(dfd);
    return 0;
}

运行结果

相关推荐
码农爱java2 小时前
Spring Boot 中的监视器是什么?有什么作用?
java·spring boot·后端·面试·monitor·监视器
skyshandianxia4 小时前
Java面试八股之如何提高MySQL的insert性能
java·mysql·面试
一颗星的征途5 小时前
宝塔-Linux模板常用命令-centos7
linux·运维·服务器
打打打劫5 小时前
Linux字符设备驱动
linux
cssl-虞老师5 小时前
Ubuntu安装Docker
linux·ubuntu·docker
super_Dev_OP5 小时前
Web3 ETF的主要功能
服务器·人工智能·信息可视化·web3
Xu-小安安6 小时前
linux less命令详解
linux·less
huhy~6 小时前
PDI-kettle工具连接本地虚拟机Ubuntu上的数据库
linux·数据库·ubuntu
w_outlier6 小时前
gcc/g++的四步编译
linux·c++·gcc·g++
小梁不秃捏6 小时前
计算机网络之以太网
服务器·计算机网络·信息与通信