- 论坛徽章:
- 0
|
自己练习,多线程复制文件,同一文件下,多线程并发写入同一文件的不同部分。
思路是,提前为每个线程分配好写入内容大小,每个线程执行fopen获取单独的文件描述符,然后按分配的写入大小,fseek到不同的位置,并发写入内容。
但是写入的内容总是错乱。
- #include <stdio.h>
- #include <sys/stat.h>
- #include <string.h>
- #include <pthread.h>
- #include <unistd.h>
- #include <stdlib.h>
- #define BUFF_SIZE 512
- #define PTHREAD_NUMBER 4
- typedef struct copy_block
- {
- char fin[BUFF_SIZE];
- char fout[BUFF_SIZE];
- long start; //起始位置
- long segment_size; //分段大小
- int id; //虚拟线程id
- } __attribute__((packed)) page;
- long file_size(char *filename)
- {
- struct stat fstat;
- memset(&fstat, 0, sizeof(fstat));
- stat(filename, &fstat);
- return fstat.st_size;
- }
- //单线程任务逻辑
- void pthread_copy(void *arg)
- {
- //转换指针类型
- page *p = (page *)arg;
- //每个线程单独打开文件
- FILE *fin = fopen(p->fin, "r");
- FILE *fout = fopen(p->fout, "wb+");
- //移动流到偏移位置
- int res1 = fseek(fin, p->start, SEEK_SET);
- int res2 = fseek(fout, p->start, SEEK_SET);
- //开始复制
- char buffer[BUFF_SIZE]; //读写区
- long read_size = BUFF_SIZE; //预设读写大小
- long left = p->segment_size; //剩余大小,初始化为任务总大小
- long reade_len = 0; //读取文件大小
- long total_len = 0;
- //当剩余大小大于0时保持复制
- while (left > 0)
- {
- //如果文件剩余大小小于预设读写大小,则按剩余大小读取
- if (read_size > left)
- {
- read_size = left;
- }
- //读取文件
- reade_len = fread(buffer, 1, read_size, fin);
- total_len += reade_len;
- //写入文件
- if (reade_len > 0)
- {
- fwrite(buffer, 1, reade_len, fout);
- }
- //剩余大小减去已读写大小
- left = left - reade_len;
- }
- //复制完成关闭文件
- fclose(fin);
- fclose(fout);
- pthread_exit(NULL);
- }
- //开启多线程任务
- int multi_copy(char *src, char *dest)
- {
- //判断文件是否存在,以及是否具有读取权限
- int file_exist = access(src, 4);
- if (file_exist != 0)
- fprintf(stderr, "源文件不存在");
- //获取文件大小
- long fsize = file_size(src);
- //真正运行线程数量
- int real_pthread_number = PTHREAD_NUMBER;
- if (fsize < PTHREAD_NUMBER)
- real_pthread_number = 1;
- //给任务结构体分配内存
- page *p;
- p = malloc(sizeof(*p) * PTHREAD_NUMBER);
- long offset = 0; //文本偏移量
- long segment = fsize / real_pthread_number; //分段长度
- long segment_remainder = fsize % real_pthread_number; //分段后剩余长度
- //给每个线程分配任务
- for (int i = 0; i < real_pthread_number; i++)
- {
- //分配复制任务的文件大小
- if (i + 1 == real_pthread_number)
- {
- p[i].segment_size = segment + segment_remainder;
- }
- else
- {
- p[i].segment_size = segment;
- }
- //确定任务的起止位置
- p[i].start = offset;
- offset = offset + p[i].segment_size;
- //文件路径存入任务
- strncpy(p[i].fin, src, strlen(src));
- strncpy(p[i].fout, dest, strlen(dest));
- //分配虚拟线程id
- p[i].id = i;
- }
- //创建线程
- pthread_t work[real_pthread_number];
- for (int i = 0; i < real_pthread_number; i++)
- {
- pthread_create(&work[i], NULL, (void *)&pthread_copy, (void *)&p[i]);
- }
- //阻塞主线程
- for (int i = 0; i < real_pthread_number; i++)
- {
- pthread_join(work[i], NULL);
- }
- //释放任务结构体占用内存
- if (p != NULL)
- {
- free(p);
- p = NULL;
- }
- return 0;
- }
- int main(int argc, char *argv[])
- {
- char *src;
- char *dest;
- src = argv[1];
- dest = argv[2];
- multi_copy(src, dest);
- }
复制代码
|
|