善用搜索

linux多线程---使用mmap映射实现文件拷贝教程

一、代码实现思路

1、示意图

2、示意图注解

循环创建i个线程,将src文件分为i段拷贝到dest文件中

(1)src文件的大小为src\_size,前i-1个线程拷贝的文件大小为src\_size/(i-1),第i个线程拷贝的文件大小为src\_size%(i-1)

(2)线程i的文件偏移量=i*(src\_size(i-1)),线程i的文件拷贝位置=起始位置+线程i的文件偏移量

二、使用mmap映射---多线程拷贝代码

<pre class="brush:cpp;gutter:true;">#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
#include<sys/mman.h>
#include<unistd.h>
#include<pthread.h>

#define PTHREAD_NUM 5  //线程数

struct CopyInfo{
    char* src;
    char* dest;
    int num;
    int src_size;
};

int main(int argc,char *argv[])
{
    if(argc!=3){
        printf("please input correct parameters\n");
        return -1; 
    }   
    //1、打开文件src,dest
    int fd_src=open(argv[1],O_RDONLY);
    int fd_dest=open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0664);

    //2、使用fstat获取文件src的大小,truncate拓展文件dest的大小
    struct stat buf;
    fstat(fd_src,&buf);
    int src_size=buf.st_size;
    truncate(argv[2],src_size);
    //3、mmap创建文件src,dest的映射,判断映射返回值,关闭文件描述符
    char* mmap_src=mmap(NULL,src_size,PROT_READ,MAP_PRIVATE,fd_src,0);
    char* mmap_dest=mmap(NULL,src_size,PROT_WRITE,MAP_SHARED,fd_dest,0);
    if(mmap_src==MAP_FAILED||mmap_dest==MAP_FAILED){
        perror("mmap err");
        return -1;
    }
    printf("src_size=%d\n",src_size);
    close(fd_src);
    close(fd_dest);
    //4、对文件src的大小分段,循环创建线程,编写线程函数

    pthread_t tid[PTHREAD_NUM];
    struct CopyInfo copyInfos[PTHREAD_NUM];//创建PTHREAD_NUM个结构体
    void* pthread_copy(void *CoIn);
    for(int i=0;i<PTHREAD_NUM;++i)//每个线程使用一个结构体
    {
        copyInfos[i].src=mmap_src;//可以改进的地方
        copyInfos[i].dest=mmap_dest;//每个结构体的src、dest、src_size大小一样,可以写在一个结构体中
        copyInfos[i].num=i; //可以将num单独写在一个结构体中,然后创建结构体数组
        copyInfos[i].src_size=src_size;
        pthread_create(&tid[i],NULL,pthread_copy,(void*)&copyInfos[i]);
    }
    //5、循环销毁线程,关闭mmap映射
    for(int i=0;i<PTHREAD_NUM;++i)
    {
        pthread_join(tid[i],NULL);
    }

    munmap(mmap_src,src_size);
    munmap(mmap_dest,src_size);

    return 0;
}

void* pthread_copy(void *CopyInfo)
{
    struct CopyInfo* CoIn=(struct CopyInfo*)CopyInfo;
    int par_lseek=CoIn->num*(CoIn->src_size/(PTHREAD_NUM-1));//par_lseek分段偏移量,计算出每段拷贝线程的距离文件起始位置的偏移量
    printf("i=%d  lseek=%d\n",CoIn->num,par_lseek);
    if(CoIn->num<(PTHREAD_NUM-1))
    {
        int copy_size=CoIn->src_size/(PTHREAD_NUM-1);
        memcpy(CoIn->dest+par_lseek,CoIn->src+par_lseek,copy_size);//CoIn->dest+par_lseek:dest文件的起始位置+分段偏移量
    }else //copyInfo->num==(PTHREAD_NUM-1)
    {
        int copy_size=CoIn->src_size%(PTHREAD_NUM-1);
        memcpy(CoIn->dest+par_lseek,CoIn->src+par_lseek,copy_size);
    }
    //memcpy(CoIn->dest+par_lseek,CoIn->src+par_lseek,copy_size); //可以在此处内存拷贝
    return NULL;
}

三、运行截图

注意事项:

gcc 01\_mmap\_pthread\_copy.c -lpthread 多线程代码编译要加-lpthread,否则会报错

gcc对.c文件直接编译后,会生成a.out的可执行文件

一入编程深似海,多学多查多动手

\#include<stdio.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<string.h>#include<sys/mman.h>#include<unistd.h>#include<pthread.h>
\#define PTHREAD\_NUM 5 //线程数
struct CopyInfo{ char* src; char* dest; int num; int src\_size;};

发表评论
退出移动版