🔥 博客主页 : 我要成为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
执行文件拷贝任务,处理源文件和目标文件的读写操作。
- 参数校验 -> 任务量计算 -> 进程创建 -> 子进程执行文件拷贝。
- 子进程根据任务量和位置执行读写操作,直到完成整个文件的拷贝。
代码实现
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;
}
运行结果