多线程编程实例:不带缓冲的多线程文件复制

         其实这个程序实际意义并不大,写这个主要是为之后写基于TCP的多线程断点文件传输热身,

但由于在写这个程序的时候遇到了很多值得注意的问题,所以就特地写个博客来简单阐述一下。

先贴上代码,因为我是在学习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读到的位置,这样就发生了数据重复.

所以必须为每个线程都开辟一个文件描述符,让每个线程都独享一个文件偏移量,保证即使发生线程切换也不会导致传输了错误数据.


所以写这个程序我了解到很多关于线程共享与同步的问题.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值