多进程聚写(一)

这段时间一直在跟着实验室学习,终于算是把《UNIX环境高级编程》的重点章节看完了,就差最后一个小作业了,就是多进程聚集写(Multi-Writing),要求如下:

    多进程聚集写(multi-writing)
     利用单生产者和多消费者模型,利用管道实现一个多进程协作拷贝文件的程序。一个进程读文件另外n个进程写,完成1G的文件并行拷贝。
     要求:
     不能出现数据丢失
     n个消费者进程是子进程
     每个消费者进程采用pwrite()去写文件(如何确定写入偏移量?)
     程序运行退出后,使用md5sum命令验证源文件(1GB)与目标文件的内容是否一致。

      自己思考了一下再加上学长的一些意见,大概想出三种实现方式吧。分三次写完,第一个最简单。

    一般多进程问题都需要同步,这里有两个地方需要考虑。一是多个消费者读取管道数据时,这里我们利用Unix管道自身的一些特性(即当管道中没有数据时阻塞读进程,当管道中数据满时阻塞写进程)就省去这个麻烦了。二是多个写进程往文件中写数据时,需要分开来写,不然会出现相互覆盖导致数据丢失,所以只需考虑第二个问题。

    不过如果多个写进程都知道自己要往文件的那一块写、写多少,而不是按顺序写下去,就可以避免这个问题。由此我们可以在生产者从文件中读取数据时就把数据长度、偏移量等信息保存下来,写在一个结构里。然后让写进程根据自己得到的数据块的偏移量写入文件中,那么他们之间的工作就不会干扰,也不存在先写后写结果不同的问题。

    然而真正写代码的时候发现还需要考虑一些问题:

1.怎么把那个结构字符串化写到管道里,怎么从子进程恢复结构信息

2.父进程怎么判定所有子进程全部终结了

    考虑清楚这两个问题就可以写出代码了。下面代码不是最终的版本,有好多东西没优化,只作参考。

    在测试的时候还发现了一个问题,就是写入管道时串的大小问题。如果长度超过4096,那么复制的较大文件(比如超过1G)就会有损失,不影响使用,但是md5值不同。如果少于4096就不会有这个问题,个人猜想应该和文件系统最小块为4K有关系。很巧合的是昨天下午看《Unix网络编程:卷1》时,作者也提到了这个问题(P72 3.9),但并未给解释,待有时间再来探索吧。

/*************************************************************************
	> File Name: multiProcess.c
	> Author: R_Kevin
	> Mail: 561705440@qq.com 
	> Created Time: 2014年03月05日 星期三 13时40分03秒
 ************************************************************************/

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<fcntl.h>
#include<string.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<errno.h>

#define MAXLENGTH	409
#define TILE	50
typedef struct {
	int length;
	char buf[MAXLENGTH];
	off_t offset;
} node;

pid_t r_wait(int *stat_loc);
void mysprintf(char*,char*,int);
char inpipe[MAXLENGTH+TILE],outpipe[MAXLENGTH+TILE];

int main(){
	pid_t pid;
	int i = 10;
	int infiled,outfiled;
	int fd[2];
	off_t oldoffset = 0;
	infiled = open("/home/kevin/Desktop/Test/infile",O_RDONLY);
	outfiled = open("/home/kevin/Desktop/Test/outfile",O_WRONLY|O_TRUNC);
	if(infiled == -1)
		puts("wrong1");
	if(outfiled == -1) 
		puts("wrong2");
	if( pipe(fd) == -1)
		puts("Error(pipe)");
	while(i--){
		pid = fork();
		 if(pid == 0){
			//child;
			node outnode;
			int n;
			close(fd[1]);
			while(1){
				n = read(fd[0],outpipe,MAXLENGTH+TILE);
				if(n == -1){
					puts("Reading abandon");
					exit(0);
				}
				if(!n){
					break;
				}
				sscanf(outpipe,"%d+%ld+",&outnode.length,&outnode.offset);
				pwrite(outfiled,outpipe+32,outnode.length,outnode.offset);
			}
			exit(0);
		 }
	}
	if(pid>0){
		node innode;
		close(fd[0]);
		while( innode.length = read(infiled,innode.buf,MAXLENGTH)){
			if(innode.length == -1){
				puts("Writing abandon");
				return 0;
			}
			innode.offset = oldoffset;
			oldoffset += innode.length;
			sprintf(inpipe,"%10d+%20ld+",innode.length,innode.offset);
			mysprintf(inpipe,innode.buf,innode.length);
			write(fd[1],inpipe,MAXLENGTH+TILE);
		}
		close(fd[1]);
		while(r_wait(NULL)>0);
		close(infiled);
		close(outfiled);
	//	printf("PIPE_BUFER IS %d\n",pathconf(_PC_PIPE_BUF));
	}
	return 0;
}

void mysprintf(char *obj,char *source,int len){
	int i=0;
	for(;i<len;i++)
		obj[32+i]=source[i];
}

pid_t r_wait(int *stat_loc){
	int retval;
	while(((retval = wait(stat_loc)) == -1) && (errno == EINTR));
	return retval;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值