Linux下C++多线程文件复制程序仅生成空文件问题求助
问题根因&修复点
sendfile参数顺序写反:Linux系统sendfile的参数顺序是sendfile(输出文件描述符, 输入文件描述符, 偏移量指针, 传输长度),你把读写fd传反了,自然没有数据写入目标文件。- 偏移量完全未正确计算:PART结构体里的offset没有赋值,你还用块大小当偏移量定位写入位置,直接跳过了文件开头的内容,且offset用了指针类型未分配内存,传空指针会导致调用失败。
- 统计文件大小的时机错误:你在调用
stat(file, &f_stat)之前就用f_stat.st_size计算分块大小,拿到的是未初始化的垃圾值,分块逻辑完全无效。 - 变量名错误:循环条件里写的
number_threads不存在,你实际定义的变量名是threads_number,编译都过不了。 - 线程串行执行:你创建线程后立刻调用
pthread_join,等于前一个线程执行完才会创建下一个,完全没用到多线程并行的能力。 - 全局文件描述符线程不安全:多个线程同时改写全局的
fin、fout变量会导致数据竞争,且每次打开文件后未关闭,存在资源泄漏,main函数里打开的fin1、fout1也完全没有用到。 - 输出路径处理错误:你的参数第二个是目标目录,你直接把目录路径当作文件打开会失败,需要拼接源文件名到目标目录下生成完整的输出文件路径。
修复后完整代码
/*Multithreads file copier*/ #include <fcntl.h> #include <pthread.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <sys/sendfile.h> #include <unistd.h> #include <string.h> #include <libgen.h> const char* file; char fileout_path[PATH_MAX]; // 每个线程处理的分块信息 struct PART{ off_t offset; // 改为非指针类型,存储当前分块的起始偏移 size_t size; }; void *Copy (void *data) { struct PART *mypart = (struct PART *) data; // 每个线程独立打开文件,避免共享fd的偏移竞争 int fin = open(file, O_RDONLY, 0); int fout = open(fileout_path, O_WRONLY, 0644); if (fin < 0 || fout < 0) { perror("open file failed"); pthread_exit(NULL); } // 定位输出文件的写入位置 lseek(fout, mypart->offset, SEEK_SET); off_t offset = mypart->offset; sendfile(fout, fin, &offset, mypart->size); printf("thread处理块:偏移%ld,大小%ld\n", mypart->offset, mypart->size); close(fin); close(fout); pthread_exit(0); } int main(int argc, char *argv[]) { if (argc < 3) { printf("用法:./a.out <源文件路径> <目标目录> <线程数(默认4)>\n"); return 1; } int threads_number = 4; if (argv[3] != NULL) { threads_number = atoi(argv[3]); if (threads_number <= 0) threads_number = 4; } pthread_t tid[threads_number]; struct stat f_stat; struct PART part[threads_number]; file = argv[1]; // 先获取源文件大小再计算分块 if (stat(file, &f_stat) < 0) { perror("获取源文件信息失败"); return 1; } // 拼接目标文件完整路径:目标目录+源文件名 char* filename = basename((char*)file); snprintf(fileout_path, sizeof(fileout_path), "%s/%s", argv[2], filename); // 预创建目标文件并调整大小,避免多线程写入时文件扩展竞争 int fout_tmp = open(fileout_path, O_WRONLY|O_CREAT|O_TRUNC, 0644); if (fout_tmp < 0) { perror("创建目标文件失败"); return 1; } ftruncate(fout_tmp, f_stat.st_size); close(fout_tmp); // 计算每个线程的分块偏移和大小 unsigned long part_size = f_stat.st_size / threads_number; for(int i =0; i < threads_number; i++) { part[i].offset = i * part_size; if (i == threads_number -1) { part[i].size = f_stat.st_size - part[i].offset; } else { part[i].size = part_size; } } // 先创建所有线程,再统一等待执行完成,实现并行 for (int j = 0; j < threads_number; j++) { pthread_create(&tid[j], NULL, Copy, (void *)&part[j]); } for (int j = 0; j < threads_number; j++) { pthread_join(tid[j], NULL); } printf("所有线程执行完成,文件复制成功\n"); return 0; }
编译运行方法
编译需要链接pthread库:g++ copy.cpp -o copy -lpthread
运行命令示例:./copy test.txt /tmp 8
内容的提问来源于stack exchange,提问作者Zahra
相关产品推荐
相关产品推荐

