网上已经有很多代码,本来打算理解一下别人的代码,拷贝过来执行就可以了,但是找了两个博客的代码,执行都报错了,于是就研究了一下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;
}
执行结果如下图:
标签:info,映射,int,linuc,C语言,线程,offset,拷贝,多线程
来源: https://blog.csdn.net/weixin_40547071/article/details/87885518