小作业01:多进程拷贝

作业要求:实现多进程分段拷贝文件,可指定拷贝的文件的路径,和拷贝使用的进程数,

分析

系统函数有:

  • fork
    • 进程创建
  • waitpid
    • 子进程死亡回收
  • stat
    • 获取文件大小
  • open
    • 打开文件
  • mmap
    • 内存映射

难点分析

也算不上什么难点,只不过需要对每个进程所需要的写入的片段字节大小和和偏移量思考一下,其余的无非就是细节上的问题。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<string.h>

int main (int argc, char* argv[]){
if(argc != 4){
printf("./mcp rfilepath wfilepath n\n");
exit(1);
}

int n = atoi(argv[3]);
if(n > 0 && n < 10 ){
printf("进程数为 %d\n", n);
}else {
printf("进程数默认为 %d\n", n);
n = 1;
}

int fd_r = open(argv[1], O_RDONLY);
if(fd_r == -1){
perror("read init error");
exit(1);
}
struct stat fr;
fstat(fd_r,&fr);
size_t size = fr.st_size;

int fd_w = open(argv[2], O_RDWR | O_CREAT |O_TRUNC, 0777);
if(fd_w == -1){
perror("write init error");
exit(1);
}

//拓宽写文件
ftruncate(fd_w, size);

//对读文件进行mmap
char* mm_r = mmap(NULL, size, PROT_READ, MAP_SHARED, fd_r, 0);
if(mm_r == MAP_FAILED){
perror("mmap readfile error");
exit(1);
}
close(fd_r);
//对写文件进行mmap
char* mm_w = mmap(NULL, size, PROT_READ| PROT_WRITE, MAP_SHARED, fd_w, 0);
if(mm_w == MAP_FAILED){
perror("mmap writefile error");
exit(1);
}
close(fd_w);

//根据所选进程数求出字节数和进程数
int len = size/n;
//最后一个进程需要处理的子节数
int len_end = len + (size%len);

pid_t pid ,wpid;
int i=0;
for (; i < n; i++)
{
pid = fork();
if(pid == 0){
break;
}else if(pid < 0){
perror("fork error");
exit(1);
}
}
if(i < n-1 || n == 1 && pid == 0){
//前倒数第一个子进程们
printf("第 %d 个子进程 ,偏移的数据长度为 %u 字节, 复制了%u字节\n", i+1, len*i, len);
memmove(mm_w+(len*i), mm_r+(len*i), len);
}else if(i == n-1 && pid == 0){
//倒数第一个子进程
printf("最后一个子进程, 偏移的数据长度为 %u 字节,复制了%u字节\n", len*i, len_end);
memmove(mm_w+(i*len), mm_r+(i*len), len_end);
}else {
//主进程//进行回收
do{
wpid = waitpid(-1, NULL, WNOHANG);
if(wpid > 0){
n--;
}
}while(wpid !=-1 || n > 0 );
munmap(mm_r, size);
munmap(mm_w, size);
}
return 0;
}