多线程编程实例:不带缓冲的多线程文件复制
2014-04-25 23:34
204 查看
其实这个程序实际意义并不大,写这个主要是为之后写基于TCP的多线程断点文件传输热身,
但由于在写这个程序的时候遇到了很多值得注意的问题,所以就特地写个博客来简单阐述一下。
先贴上代码,因为我是在学习apue的时候写这个程序的,所以里面会用到头文件apue 和 错误处理函数 error.c
测试环境:linux12.03.
具体代码大家网上也可以搜到.
然后简单地除以3 得到的字节数就是每个线程实际要传输的数据量,因为文件容量除以3得到的结果不一定是整数,
所最后一个线程要拿出来单独处理,它要传输剩余的文件字节数.
2.根据每个线程要处理的字节数很容易就可以算出每个线程的读取文件的偏移量的开始位置.这里pthread_create我传入了一个结构体,
这个结构体的成员变量就是对应线程要处理的文件偏移量开始位置 以及 要处理的字节数.
3.在线程启动函数 ( func )里面 都开辟了一个目标文件和源文件的文件描述符,原因是在同一个进程中,所有线程都共享这些文件操作符,
意味着假如线程A 在读取期间发生了线程切换,切换到线程b,那么b线程此时的偏移量正是刚才a读到的位置,这样就发生了数据重复.
所以必须为每个线程都开辟一个文件描述符,让每个线程都独享一个文件偏移量,保证即使发生线程切换也不会导致传输了错误数据.
所以写这个程序我了解到很多关于线程共享与同步的问题.
但由于在写这个程序的时候遇到了很多值得注意的问题,所以就特地写个博客来简单阐述一下。
先贴上代码,因为我是在学习apue的时候写这个程序的,所以里面会用到头文件apue 和 错误处理函数 error.c
测试环境:linux12.03.
具体代码大家网上也可以搜到.
#include <unistd.h> #include <pthread.h> #include <sys/stat.h> #include <stdio.h> #include <fcntl.h> #include <string.h> #include "apue.h" char srcfile[20] = "test.c\0"; typedef struct workInfo { long pos; long length; }workInfo; void *func (void *ptr) { workInfo *s = (workInfo *)ptr; long int n; //apue 里面解释数组设置成4096字节效果最好 char buff[4096]; // 每个线程都要打开一个读和写文件描述符,以保证每个线程都有一个属于自己的文件偏移量 // 因此线程间不能共享同一个文件的偏移量. int wno = open("target",O_WRONLY); int fileno = open(srcfile,O_RDONLY); //根据分配的工作每个线程设置自己的 读 文件描述符的偏移量开始位置. lseek(fileno,s->pos,SEEK_SET); //根据分配的工作每个线程设置自己的 写 文件描述符的偏移量开始位置. lseek(wno,s->pos,SEEK_SET); long total = s->length; while ( total > 0 ) { long max =4096 < total ? 4096:total; printf("max: %ld total: %ld\n",max,total); if ((n = read(fileno,buff,max)) >0) { if (write(wno,buff,n) != n) err_sys("write error"); else { total-=n; printf("n: %ld %ld \n",n,total); } } if (n<0) err_sys("read error"); } } int main() { const int number = 3; //线程数量. pthread_t pid[number]; int rno = open(srcfile,O_RDONLY); struct stat s; fstat(rno,&s); long length = s.st_size; printf("the length of the file is: %ld bytes\n",length); //建立一个新文件 int wno = open("target",O_WRONLY|O_CREAT|O_TRUNC,S_IWUSR|S_IRUSR); //后面不再使用这两个文件描述符,可以在此处关闭. close(rno); close(wno); //每个线程应该要传送的字节数 long each = length /number; unsigned int times; workInfo ss[number]; for (times = 0; times<number-1; ++times) { ss[times].pos =each * times; ss[times].length = each; pthread_create(&pid[times],NULL,func,(void*) &ss[times] ); // sleep(1); } //最后一个线程的配置要特殊处理,因为length/number得出的结果不一定是整数,所以最后一个线程要负责传送余下的所有文件内容 ss[times].pos = each *times; ss[times].length = length - each*times; pthread_create(&pid[times],NULL,func,(void*) &ss[times]); int i; for (i=0; i<number;++i) pthread_join(pid[i],NULL); }
说说大概设计思路:
1. 这个程序我开辟了3个工作线程(不包括主线程),首先读取要传输文件的大小,单位是字节,然后简单地除以3 得到的字节数就是每个线程实际要传输的数据量,因为文件容量除以3得到的结果不一定是整数,
所最后一个线程要拿出来单独处理,它要传输剩余的文件字节数.
2.根据每个线程要处理的字节数很容易就可以算出每个线程的读取文件的偏移量的开始位置.这里pthread_create我传入了一个结构体,
这个结构体的成员变量就是对应线程要处理的文件偏移量开始位置 以及 要处理的字节数.
3.在线程启动函数 ( func )里面 都开辟了一个目标文件和源文件的文件描述符,原因是在同一个进程中,所有线程都共享这些文件操作符,
意味着假如线程A 在读取期间发生了线程切换,切换到线程b,那么b线程此时的偏移量正是刚才a读到的位置,这样就发生了数据重复.
所以必须为每个线程都开辟一个文件描述符,让每个线程都独享一个文件偏移量,保证即使发生线程切换也不会导致传输了错误数据.
所以写这个程序我了解到很多关于线程共享与同步的问题.
相关文章推荐
- 多线程编程实例:不带缓冲的多线程文件复制(使用队列,互斥,条件变量)
- 多线程编程实例:不带缓冲的多线程文件复制 (使用pread pwrite版本)
- java向文件中写入内容,字节流,字符流,缓冲,复制文件,设置字符编码 实例
- java多线程复制文件的实例代码
- [转]C#多线程编程实例实战
- 批处理实例:文件复制辅助批处理
- 多线程编程实例
- 在Node.js中实现文件复制的方法和实例
- C#拷贝文件和复制文件夹实例代码 C#拷贝文件
- 多线程编程实例
- 零基础学Qt 4编程实例之三:勾三股四弦必五—文件包含语句与标准库的使用
- 多线程复制文件
- python复制文件的方法实例详解
- 多线程 读写锁 实例--同步操作双向链表(unix环境高级编程)
- Javascript & DHTML 实例编程(教程)(三)初级实例篇1―上传文件控件实例
- 多线程编程实例----多线程同时排序
- Linux 平台多线程编程实例
- java多线程读写文件实例
- 多线程编程同步机制之临界区编程实例
- web 编程中实现文件上传的服务端实例