linux下c语言实现多线程文件复制【转】

转自:https://www.cnblogs.com/zxl0715/articles/5365989.html

1、具体思路
把一个文件分成N份,分别用N个线程copy,
每个线程只读取指定长度字节大小的内容
最后一个线程的源文件所指定的结束位置是文件的实际大小
每个线程读取指定源文件部分的起始位置和结束位置的内容到缓冲区
每个线程将缓存中的内容写入目的文件的指定开始位置和结束位置
主线程必须等到所有线程copy完成后才能退出

2.有关文件操作的函数
2.1. 文件的打开和关闭
2.1.1 open()函数
       open()函数的作用是打开文件, 其调用格式为:
         int open(char *filename, int access);
  该函数表示按access的要求打开名为filename的文件,
  返回值为文件描述字
  open()函数打开成功, 返回值就是文件描述字的值(非负值), 否则返回-1。
2.1.2 close()函数
       close()函数的作用是关闭由open()函数打开的文件, 其调用格式为:
          int close(int handle);
       该函数关闭文件描述字handle相连的文件。
2.2.读写函数
2.2.1 read()函数
       read()函数的调用格式为:
          int read(int handle, void *buf, int count);
       read()函数从handle(文件描述字)相连的文件中, 读取count个字节放到buf所指的缓冲区中,
       返回值为实际所读字节数, 返回-1表示出错。返回0 表示文件结束。

2.2.2 write()函数
       write()函数的调用格式为:
          int write(int handle, void *buf, int count);  

       write()函数把count个字节从buf指向的缓冲区写入与handle相连的文件中,
       返回值为实际写入的字节数
2.3.随机定位函数
lseek()函数
       lseek()函数的调用格式为:
         int lseek(int handle, long offset, int fromwhere);
       该函数对与handle相连的文件位置指针进行定位, 功能和用法与fseek() 函数相同。

3.源文件(copyfn.c)
源文件在ubuntu10.04下编译通过

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>

#define THREADS_COUNT 3
#define THREADS_BUFF_SIZE 1*1024
struct thread_block
{
    int infd; ///源文件句柄
    int outfd;//目的文件句柄
    size_t start;///文件的写入起始位置
    size_t end; ///文件写入的终止位置
};

void usage()
{
    printf("copy %%src %%dst\n");
}
///获取文件大小
size_t get_filesize(int fd)
{
    struct stat st;
    fstat(fd,&st);
    return st.st_size;
}
void *thread_copy_fn(void *arg);
int main(int argc,char *argv[])
{
    if(argc < 3)
    {
        usage();
        return -1;
    }
    ///打开文件
    int infd = open(argv[1],O_RDONLY);
    int outfd = open(argv[2],O_CREAT|O_WRONLY,0644);
    // 0644也就是-文件所有者有读写权限,组有读权限,其他用户有读权限
    if(infd == -1|| -1 ==outfd)
    {
        printf("error while open file \n");
        return -1;
    }
    size_t file_size = get_filesize(infd);

    size_t thread_size = THREADS_COUNT;
    struct thread_block *blocks = (struct thread_block *)
        malloc(sizeof(struct thread_block )* thread_size);
    size_t percent = file_size / thread_size;
    printf("filesize = %d\t percent_blocks = %d\n",            file_size,percent);
    int i = 0;
    //init-thread-block
    for(; i < thread_size;++i)
    {
        blocks[i].infd = infd;
        blocks[i].outfd = outfd;
        blocks[i].start = i * percent;
        blocks[i].end = blocks[i].start + percent;
    }
    //the last thread
    blocks[i].end = file_size;
    pthread_t ptid[thread_size];
    ///创建线程
    for(i = 0 ; i < thread_size; ++i)
    {
        pthread_create(&ptid[i],NULL,thread_copy_fn,&(blocks[i]));
    }
    ///线程Join
    for(i = 0 ; i < thread_size; ++i)
   {
        pthread_join(ptid[i],NULL);
    }
    ///释放资源
    free(blocks);
    close(infd);
    close(outfd);
    printf("Copy Successfully \n");
    return 0;
}

void *thread_copy_fn(void *arg)
{
    struct thread_block *block = (struct thread_block *)arg;
    char buf[THREADS_BUFF_SIZE];
    int ret;
    size_t count = block->start;

    printf("In Thread\t%ld\nstart = %ld\t end = %ld\n",            pthread_self(),block->start,block->end);

    ///lseek到同样的位置
    ret = lseek(block->infd,block->start,SEEK_SET);
    ret = lseek(block->outfd,block->start,SEEK_SET);
    int bytes_read;
    int bytes_write;
    while(count < block->end)
    {
        bytes_read = read(block->infd,buf,sizeof(buf));
        if(bytes_read >0)
        {
            printf("thread = %ld\t read = %ld\t count %d\n",                    pthread_self(),bytes_read,count);
            count += bytes_read;

            //read()返回-1,同时errno为EINTR,表示读的过程中遇到了中断
            if((bytes_read == -1)&&(errno !=EINTR))
                    break;
            char *ptr_write = buf;
            while((bytes_write = write(block->outfd,ptr_write,bytes_read))!=0)
            {
                //write()会返回-1,同时errno为EINTR,表示在写的过程中遇到了中断
                if((bytes_write == -1)&&(errno!=EINTR))
                    break;
                if(bytes_write == bytes_read)
                    break;
                else if(bytes_write > 0)
                {
                    ptr_write += bytes_write;
                    bytes_read -= bytes_write;
                }
                printf("thread = %ld\t write = %ld\t read %d\n",                    pthread_self(),bytes_write,bytes_read);
            }//end-write;
            ///error while write
            if(bytes_write == -1)
                break;

        }
    }
    printf("#####Thread exit %ld#####\n",pthread_self());
    pthread_exit(NULL);
}
本文欢迎转载,转载请注明作者与出处

原文地址:https://www.cnblogs.com/sky-heaven/p/11022839.html

时间: 2024-10-29 11:09:31

linux下c语言实现多线程文件复制【转】的相关文章

linux 下C语言编程库文件处理与Makefile编写

做开发快3年了,在linux下编译安装软件算是家常便饭了.就拿gcc来说,都有不下10次了,可基本每次都会碰到些奇奇怪怪的问题.看来还是像vs.codeblocks这样的ide把人弄蠢了.便下定决心一定要好好学习下如何在linux下纯手工gcc编译c项目.今天学了2点,一个是库文件处理,另一个是makefile编写. 学习的系统是centos6.6,编译升级的gcc4.8.2,明天写个博客总结下这回gcc安装的过程,每次都能学到些东西. gcc的编译过程 首先需要清楚gcc编译做了些什么 源文件

Linux下C语言多线程,网络通信简单聊天程序

原文:Linux下C语言多线程,网络通信简单聊天程序 功能描述:程序应用多线程技术,可是实现1对N进行网络通信聊天.但至今没想出合适的退出机制,除了用Ctr+C.出于演示目的,这里采用UNIX域协议(文件系统套接字),程序分为客户端和服务端.应用select函数来实现异步的读写操作. 先说一下服务端:首先先创建套接字,然后绑定,接下进入一个无限循环,用accept函数,接受“连接”请求,然后调用创建线程函数,创造新的线程,进入下一个循环.这样每当有一个新的“连接”被接受都会创建一个新的线程,实现

LINUX下C语言编程调用其他函数、链接头文件以及库文件

LINUX下C语言编程经常需要链接其他函数,而其他函数一般都放在另外.c文件中,或者打包放在一个库文件里面,我需要在main函数中调用这些函数,主要有如下几种方法: 1.当需要调用函数的个数比较少时,可以直接在main函数中包含该文件,比如一个文件夹下包含add.c和main.c文件: 方法一: 文件add.c定义两个整数相加的函数,code如下: #include <stdio.h> #include <math.h> int add(int a,int b) { int z;

linux下使用math.h头文件-l与-L参数

遇到一个问题就是,c语言用到sqrt时,明明已包含math.h文件,却仍提示未定义,所以上网招答案的: gcc -lm 以下转自http://bbs.csdn.net/topics/330105678 ·-l参数和-L参数 -l参数就是用来指定程序要链接的库,-l参数紧接着就是库名,那么库名跟真正的库文件名有什么关系呢?就拿数学库来说,他的库名是m,他的库文件名是libm.so,很容易看出,把库文件名的头lib和尾.so去掉就是库名了 好了现在我们知道怎么得到库名,当我们自已要用到一个第三方提供

linux下C语言函数执行时间统计

转载:http://blog.csdn.net/linquidx/article/details/5916701#t5 写好程序,用gcc编译,带上-pg参数,然后运行以后分析gmon.out文件: 命令exp:   gprof ./test-main ./gmon.out >1.log  在1.log中会生成各函数运行情况. gprof 1.1 简介 gprof实际上只是一个用于读取profile结果文件的工具.gprof采用混合方法来收集程序的统计信息,他使用检测方法,在编译过程中在函数入口

LINUX下C语言编程基础

实验二 Linux下C语言编程基础 一.实验目的 1. 熟悉Linux系统下的开发环境 2. 熟悉vi的基本操作 3. 熟悉gcc编译器的基本原理 4. 熟练使用gcc编译器的常用选项 5 .熟练使用gdb调试技术 6. 熟悉makefile基本原理及语法规范 7. 掌握静态库和动态库的生成 二.实验步骤 1. 快捷键 Ubuntu中: 2. vim VIM是一个非常好的文本编辑器,很多专业程序员使用VIM编辑代码,即使以后你不编写程序,只要跟文本打交道,都应该学学VIM,可以浏览参考一下普通人

UNIX/Linux下C语言的学习路线

一.工具篇 “公欲善其事,必先利其器”.编程是一门实践性很强的工作,在你以后的学习或工作中,你将常常会与以下工具打交道, 下面列出学习C语言编程常常用到的软件和工具. 1.操作系统    在UNIX或Linux系统中学习C很方便,所以在开始您的学习旅程前请先选择一个UNIX或Linux操作系统,目前可供个人免费使用的UNIX或Linux系统有FreeBSD.RedHat Linux.SUSE Linux等,而且在安装包中还提供很多实用的工具,如:gcc, make等. 如果您一直使用Window

Linux下C语言执行过程(预处理,编译,汇编,链接,执行)

1.C语言的执行过程包括5个步骤:分别是:预处理,编译,汇编,链接,执行 第一步:编写C源代码,截图如下: 2.预处理,命令为:gcc -E variable.c -o variable.i(这步的作用是文件的展开和宏替换),生成的文件类型是.i类型的. 3.编译:命令为:gcc -S variable.i -o variable.s,这里的.s文件就成了会变语言,截图如下: 4.汇编,命令是:gcc -c variable.s -o variable.o,截图如下: 5,链接:命令:gcc -

Linux下目录的合并以及文件的覆盖

有两个目录test和new,test目录下有目录和文件,new目录下有更改过的一些test下的目录和文件,以及一些新增的文件,现在对两个目录进行合并以及覆盖test下的旧文件. cp -frap new/* test/ 命令其实非常简单,解释下: -f 强制覆盖,不询问yes/no(-i的默认的,即默认为交互模式,询问是否覆盖)-r 递归复制,包含目录-a 做一个备份,这里可以不用这个参数,我们可以先备份整个test目录-p 保持新文件的属性不变 记住一点就是,实现合并和覆盖是用cp,而不是mv