多线程copy文件,另加进度条显示 分类: C语言学习 2015-06-12 16:24 87人阅读 评论(0) 收藏

/*Ubuntu 14.04平台下
* 利用多线程 mmap文件内存共享
* 实现文件拷贝
*/

/*more thread copy files
*  默认情况下开启5个线程
*/
#include <stdio.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>
#include <sys/types.h>

/*thread number*/
#define T_NUM 5
#define ITEMS 50

typedef struct{
    /*off size,file size,thread identifier */
    int off,size,t_no;
}arg_t;

void err_sys(void *str)
{
    perror(str);
    exit(1);
}

void err_usr(char *str)
{
    fputs(str,stderr);
    exit(1);
}

char *pch_sour_file,*pch_des_file;
int *pi_has_done;
int pnum=T_NUM;

/*arg {off,size,t_no}*/
void *pt_cp(void *arg)
{
    if(NULL==arg)
        return NULL;
    arg_t *arg_p;int i;
    char *pch,*qch;
    arg_p=(arg_t *)arg;
    pch=pch_sour_file+arg_p->off,qch=pch_des_file+arg_p->off;
    for(i=0;i<arg_p->size;i++)
    {
        *qch++=*pch++;
        pi_has_done[arg_p->t_no]++;
        /*usleep function is like to sleep*/
        usleep(5000);
    }
    return NULL;
}
void *display_pro(void * arg)
{
    int size,draw=0,sum,i,j,interval;
    size=(int)arg;
    interval=size/ITEMS;
    while(draw<ITEMS)
    {
        for(i=0,sum=0;i<pnum;i++)
            sum+=pi_has_done[i];
        j=sum/interval+1;
        for(;j>draw;draw++)    
            putchar('=');fflush(stdout);
    }
    printf("
");
    return NULL;
}
int main(int argc,char *argv[])
{
    int src,dst,i,len,off;
    struct stat statbuff;
    pthread_t *tid;
    arg_t *arg_arr;
    if(argc!=3 && argc!=4)    
        err_usr("usage:cp src dst [pthread_no]
");
    /*修改线程数*/
    if(argc==4)
        pnum=atoi(argv[3]);
    src=open(argv[1],O_RDONLY);
    if(src<0)
    {printf("fail to open %s
",argv[1]);return -1;}

    dst=open(argv[2],O_RDWR | O_CREAT | O_TRUNC,0644);
    if(dst<-1)
    {printf("fail to open %s
",argv[2]);return -1;}

    if(fstat(src,&statbuff)==-1)
    {
        err_sys("fail to stat");
        return -1;
    }

    /*创建同样的大小文件*/
    lseek(dst,statbuff.st_size-1,SEEK_SET);
    write(dst,"a",1);


    pch_sour_file=(char *)mmap(NULL,statbuff.st_size,PROT_READ,MAP_SHARED,src,0);
    if(pch_sour_file==MAP_FAILED)
    {
        err_sys("fail to mmap");
        return -1;
    }

    pch_des_file=(char *)mmap(NULL,statbuff.st_size,PROT_WRITE,MAP_SHARED,dst,0);
    if(pch_des_file==MAP_FAILED)
    {
        err_sys("fail to mmap");
        return -1;
    }

    /*close file discription*/    
    close(src);close(dst);
    /*crate pthread tid[n+1]*/
    tid=(pthread_t *)malloc(sizeof(pthread_t)*(pnum+1));
    if(NULL==tid)
    {
        err_sys("fail to malloc");
        return -1;
    }

    /*per thread copy bite*/
    /*每个线程需要的拷贝的字节数*/
    pi_has_done=(int *)calloc(sizeof(int),pnum);
    if(NULL==pi_has_done)
    {
        err_sys("fail to calloc");
        return -1;
    }    
    /*arg_arr[n] per thread task*/
    arg_arr=(arg_t *)malloc(sizeof(arg_t)*pnum);
    if(NULL==arg_arr)
    {
        err_sys("fail to malloc");    
        return -1;
    }
    /*allocating task*/
    len=statbuff.st_size/pnum,off=0;
    for(i=0;i<pnum;i++,off+=len)
        arg_arr[i].off=off,arg_arr[i].size=len,arg_arr[i].t_no=i;
    /*reminder byte add last struct arg_t*/
    arg_arr[pnum-1].size+=statbuff.st_size%pnum;
    /*create pthread to do*/        
    for(i=0;i<pnum;i++)
        pthread_create((tid+i),NULL,pt_cp,(void *)(arg_arr+i));
    /*专门显示进度的线程*/
    pthread_create((tid+pnum),NULL,display_pro,(void *)statbuff.st_size);
    for(i=0;i<pnum;i++)
        pthread_join(tid[i],NULL);
    /*关闭文件共享*/
    munmap(pch_sour_file,statbuff.st_size);
    munmap(pch_des_file,statbuff.st_size);
    /*回收内存*/
    free(tid);
    free(arg_arr);
    free(pi_has_done);
    return 0;
}


效果图如下所示:

版权声明:本文为博主原创文章,未经博主允许不得转载。

原文地址:https://www.cnblogs.com/L-Lune/p/4671282.html