---------- SUB_FUN.C #include "mul_cp.h" extern char *src_addr, *dest_addr; static char *sub_bar(int gain, int all, char *buf, int len, int num) { int block = len/num; if(len % num != 0) block += 1; int i; for(i = 0; i<block; i++) if(i <= block * gain /all) buf[i] = '>'; else buf[i] = ' '; buf[i] = 0; return buf; } void disp_bar(cp_task *task, int num) { int i, i_gain; int cur = 0, all = 0; char bar[60]; char *sch; for(i = 0; i<num; i++) all += task[i].off; while(cur < all){ usleep(1000); cur = 0; for(i = 0; i<num; i++) { i_gain = task[i].cur_gain; cur += i_gain; sch = sub_bar(i_gain, task[0].off, bar, sizeof(bar), num); printf("%s", sch); } printf("]%4.1f%%\r[", cur*100.0/all); } puts(""); } int assign_task(int src_filesize, int num, cp_task *task_sch) { int block_size; block_size = src_filesize / num; if(src_filesize % num != 0) // 如果不能整除,块大小= 总数/份数 + 1 block_size += 1; int i; for(i = 0; i < num; i++){ task_sch[i].id = i; task_sch[i].base = i * block_size; task_sch[i].off = block_size; } task_sch[num-1].off = src_filesize - block_size * (num - 1); } int parse_arg(const int argc, const char **argv, const char **src, const char **dest, int *pthread_num) { if(argc != 4) { printf("%s %s %s %s\n",argv[0], "<thread_number>", "<src file>", "<dest file>"); exit(0); } *pthread_num = atoi(argv[1]); *src = argv[2]; *dest = argv[3]; return *pthread_num; } int create_map(int src_filesize, const char *src_file, const char *dest_file, char **src_addr, char **dest_addr) { int src_fd, dest_fd; if((src_fd = open(src_file, O_RDONLY)) < 0){ perror("open src_fd"); exit(1); } if((dest_fd = open(dest_file, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0){ perror("open dest_fd"); exit(2); } lseek(dest_fd, src_filesize-1, SEEK_SET); // 目标文件大小必须和源文件大小相等方可对等映射 write(dest_fd, "", 1); *src_addr = mmap(NULL, src_filesize, PROT_READ, MAP_SHARED, src_fd, 0); if(*src_addr == MAP_FAILED){ perror("mmap"); exit(3); } *dest_addr = mmap(*src_addr + src_filesize, src_filesize, PROT_WRITE, MAP_SHARED, dest_fd, 0); if(*dest_addr == MAP_FAILED){ perror("mmap"); exit(4); } close(src_fd); close(dest_fd); } int get_filesize(const char *name) { int fd = open(name, O_APPEND); if(fd < 0) { perror("get_filesize-->open:"); exit(-1); } off_t off = lseek(fd, 0, SEEK_END); close(fd); return off; } ---------- MUL_CP.H #ifndef MUL_CP #define MUL_CP #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <assert.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <time.h> #include <sys/mman.h> #include <pthread.h> #define gotoxy(line, cols) fprintf(stderr, "\033[%d;%dH", (line),(cols)) #define my_hide_curse() fprintf(stderr, "\033[?25l") #define my_show_curse() fprintf(stderr, "\033[?25h") typedef struct { int id; int base; int off; int cur_gain; }cp_task; void disp_bar(cp_task *task, int num); static char *sub_bar(int gain, int all, char *buf, int len, int num); int assign_task(int src_filesize, int num, cp_task *task_sch); int parse_arg(const int argc, const char **argv, const char **src, const char **dest, int *pthread_num); int create_map(int src_filesize, const char *src_file, const char *dest_file, char **src_addr, char **dest_addr); #endif ---------- MUL_CP.C #include "mul_cp.h" char *src_addr, *dest_addr; // 映射的文件内存地址; static void copy(char *src_addr, char *dest_addr, cp_task *task) { char *src = src_addr + task->base; char *dest = dest_addr + task->base; int i; for(i = 0; i < task->off; i++){ task->cur_gain = i+1; dest[i] = src[i]; usleep(100); } } void *mul_cp(void *arg) { cp_task *p = arg; copy(src_addr, dest_addr, p); } void show_curse(int arg) { my_show_curse(); puts(""); exit(0); // 主线程退出, 如果没有,则其他线程继续运行 } int main(const int argc, const char *argv[]) { // 0. 初始化 signal(SIGINT, show_curse); my_hide_curse(); // 1. 命令行解析 const char *src_file; const char *dest_file; int pthread_num; setbuf(stdout, NULL); parse_arg(argc, argv, &src_file, &dest_file, &pthread_num); // 2. 获取src文件属性,如文件大小 int src_filesize; src_filesize = get_filesize(src_file); // 3. 创建映射文件 create_map(src_filesize, src_file, dest_file, &src_addr, &dest_addr); // 4. 分派任务 cp_task task_sch[pthread_num]; memset(&task_sch, 0, sizeof(task_sch)); assign_task(src_filesize, pthread_num, task_sch); // 5. 创建多线程 int i; pthread_t tid[pthread_num]; for(i = 0; i<pthread_num; i++) pthread_create(tid+i, NULL, mul_cp, task_sch+i); // 6. 显示下载进度 disp_bar(task_sch, pthread_num); // 7. 线程回收等待 for(i = 0; i<pthread_num; i++) pthread_join(tid[i], NULL); // 8. 恢复光标显示 my_show_curse(); return 0; } ---------- MAKEFILE all: gcc mul_cp.c sub_cp.c -o xcp clean: -rm xcp *.~ a.out ---------- MUL.TXT