c语言多线程拷贝,linuc下实现多线程拷贝文件(C语言版本)

本文介绍了如何通过多线程和mmap系统调用来实现大文件的高效拷贝。作者遇到从博客代码执行报错的问题,于是深入研究并实现了自己的解决方案。每个线程负责拷贝文件的一部分,线程数量可由命令行参数指定,确保灵活性。通过mmap将文件映射到内存,然后进行拷贝,最后解除映射。代码中详细解释了mmap函数的参数及其作用。
摘要由CSDN通过智能技术生成

网上已经有很多代码,本来打算理解一下别人的代码,拷贝过来执行就可以了,但是找了两个博客的代码,执行都报错了,于是就研究了一下mmap实现多线程拷贝,参考https://blog.csdn.net/woshichaoren1/article/details/85227528https://www.cnblogs.com/lianshuiwuyi/p/7506972.html实现了,代码有些不精简,可以修改更精简,这里面我使用5个线程来拷贝,实际上可以使用命令行参数指定线程的个数,这样更灵活。

整个代码的思路是:每个线程负责拷贝文件的一部分,比如5个线程,每个线程就负责五分之一的文件大小,但是要注意的是,文件的大小不一定就是5的整数倍,所以这块我是这么处理的,前四个线程拷贝的大小是offset=filesize/5,第五个线程要拷贝的大小是filesize-4*offset,其中filesize就是要拷贝文件的大小,可以使用lseek得到。

还有要注意的就是mmap这个函数,原型是:void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

1、当addr参数为NULL,内核会自己在进程地址空间中选择合适的地址建立映射;

2、length参数是需要映射的那一部分文件的长度;

3、port参数的四种取值:如果要同时具有两个及以上取值,使用 | 操作

* PROT_EXEC表示映射的这一段可执行,例如映射共享库

* PROT_READ表示映射的这一段可读

* PROT_WRITE表示映射的这一段可写

* PROT_NONE表示映射的这一段不可访问

4、flags参数,我选择MAP_SHARED,表示多个进程对同一个文件的映射是共享的,一个进程对映射的内存做了修改,另一个进程也会看到这种变化。

5、fd是代表该文件的描述符;

6、offset参数是从文件的什么位置开始映射,必须是页大小的整数倍(在32位体系统结构上通常是4K);

正是由于offset要求是页大小的整数倍,所以我代码里这块就直接为0,没有使用info->offset,因为offset不能保证一定是4k的整数倍

#include

#include

#include

#include

#include

#include

#include

#include

typedef struct Info

{

char fromFile[255];     //源文件

char toFile[255];       //目标文件

int num;            //第几个线程

int legth;    //长度

int offset;   //偏移

int filesize;    //待拷文件的大小

}Info;

void* doThread(void *arg)

{

Info *info = (Info*)arg;

int fin= open(info->fromFile,O_RDONLY);

int fout = open(info->toFile,O_RDWR);

printf("这是第%d线程,开始拷贝\n",info->num);

//每个线程里面,我都把fromFile和toFile的filesize大小映射一下

char *s_addr=(char *)mmap(NULL,info->filesize,PROT_READ,MAP_SHARED,fin,0);

char *d_addr=(char *)mmap(NULL,info->filesize,PROT_READ|PROT_WRITE,MAP_SHARED,fout,0);

//每个线程负责拷贝文件的不同部分在这里就体现出来了,拷贝的长度通过参数得知

memcpy(d_addr+info->offset,s_addr+info->offset,info->legth);

printf("第%d个线程拷贝结束\n",info->num);

munmap(d_addr,info->legth);//解除映射

munmap(s_addr,info->legth);

return NULL;

}

int main(int argc,char *argv[])

{

pthread_t *tid;

Info *info;

info=(Info *)malloc(5*sizeof(Info));

tid=(pthread_t *)malloc(5*sizeof(pthread_t));

int fd=open(argv[1],O_RDONLY);

if(fd<0)

{

perror("open src failed:");

exit(errno);

}

umask(000);

int fd2=open(argv[2],O_RDWR|O_CREAT,0777);

if(fd2<0)

{

perror("open des failed:");

exit(errno);

}

int filesize=lseek(fd,0,SEEK_END);

ftruncate(fd2,filesize);//改变文件大小,也可以用lseek,然后write一下实现,ftruncate更简单些

int offset=filesize/5;

for(int i=0;i<4;++i)

{

//前四个线程的legth都是offset,第五个线程的legth是filesize-4*offset

info[i].num=i;//我自己给线程起的编号,从0-5

strcpy(info[i].fromFile,argv[1]);

strcpy(info[i].toFile,argv[2]);

info[i].legth=offset;

info[i].offset=i*offset;

info[i].filesize=filesize;

}

//第五个线程的legth和前四个不一样

info[4].num=4;

strcpy(info[4].fromFile,argv[1]);

strcpy(info[4].toFile,argv[2]);

info[4].legth=filesize-4*offset;

printf("%d",info[4].legth);

info[4].offset=4*offset;

info[4].filesize=filesize;

for(int i=0;i<5;++i)//创建五个线程来实现文件的拷贝

{

pthread_create(&tid[i],NULL,doThread,&info[i]);

}

for(int j=0;j<5;++j)//主线程回收创建的五个线程

{

pthread_join(tid[j],NULL);

}

return 0;

}

执行结果如下图:

127d32fd73ece8ab946e1184037fe409.png

标签:info,映射,int,linuc,C语言,线程,offset,拷贝,多线程

来源: https://blog.csdn.net/weixin_40547071/article/details/87885518

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值