假设有一个超大文件,需对其完成拷贝工作。为提高效率,可采用多进程并行拷贝的方法来实现。假设文件
大小为 len,共有 n 个进程对该文件进行拷贝。那每个进程拷贝的字节数应为 len/n。 但未必一定能整除, 我们可
以选择让最后一个进程负责剩余部分拷贝工作。 可使用 len % (len/n)将剩余部分大小求出。
为降低实现复杂度, 可选用 mmap 来实现源、 目标文件的映射,通过指针操作内存地址,设置每个进程拷贝
的起始、结束位置。借助 MAP_SHARED 选项将内存中所做的修改反映到物理磁盘上。
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/mman.h>
#include<sys/wait.h>
#include<string.h>
#include <fcntl.h>
#define N 5//进程数量
int main(int argc, char *argv[])
{
if (argc!=3)
{
printf("Enter like this : ./a.out src_file dst_file");
exit(1);
}
int n;
int fd1, fd2;
//1. 指定创建子进程的个数
//2. 打开源文件
fd1 = open(argv[1], O_RDONLY);
if (fd1<0)
{
perror("open src_file error");
exit(2);
}
//3. 打开目的文件, 不存在则创建
fd2 = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0664);
if (fd2 < 0)
{
perror("open dst_file error");
exit(3);
}
//4. 获取文件大小
struct stat s_buf;
int ret = fstat(fd1,&s_buf)
if (ret<0)
{
perror("fstat error");
exit(4);
}
int size = s_buf.st_size;
if (size< N)
{
size = N;
}
//5. 根据文件大小拓展目标文件
ret = ftruncate(fd2, size);
if (ret < 0)
{
perror("ftruncate error");
exit(5);
}
//6. 为源文件创建映射
char *mp_src = (char *)mmap(NULL, size, PROT_READ, MAP_SHARED, fd1, 0);
if (mp_src == MAP_FAILED)
{
perror("mmap mp_src error");
exit(6);
}
close(fd1);
//7. 为目标文件创建映射
char *mp_des = (char *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, 0);
if (mp_des == MAP_FAILED)
{
perror("mmap mp_des error");
exit(7);
}
close(fd2);
//8. 求出每个子进程该拷贝的字节数
int bs = flen / n;
int mod = flen % bs; //求出均分后余下的字节数,让最后一个子进程处理。
char *temp_src = mp_src;//替身
char *temp_dst = mp_dst;
//9. 创建N个子进程
//10. 子进程完成分块拷贝(注意最后一个子进程拷贝起始位置)
int i;
pid_t pid;
for (i = 0; i < N; ++i)
{
printf("create %dth proc\n", i);
if ((pid = fork()) == 0)
break;
}
if (N == i) //父进程。
{
int j = 0;
for (j = 0; j < N; ++j)
wait(NULL);
}
else if (i == (N - 1)) //10.子进程拷贝,最后一个子进程,它多处理均分后剩下的字节数。
{
printf("i = %d\n", i);
memcpy(temp_dst + i*bs, temp_src + i*bs, bs + mod);
}
else if (i == 0)//第一个进程
{
printf("i = %d\n", i);
memcpy(temp_dst, temp_src, bs);
}
else//除去第一个、最后一个进程的其他进程
{
printf("i = %d\n", i);
memcpy(temp_dst + i*bs, temp_src + i*bs, bs);
}
//11. 释放映射区
munmap(mp_src, size);
munmap(mp_dst, size);
return 0;
}