如何实现多进程写一个文件

来源:互联网 发布:古墓丽影崛起低配优化 编辑:程序博客网 时间:2024/05/10 07:52

 

作者:王姗姗,华清远见嵌入式学院讲师。

如何利用多进程,来实现文件的拷贝?

在我们学习IO的时候,曾经利用文件IO函数,标准IO函数都实现了对文件的拷贝,那么在我们学习过进程间通信后,就可以创建多个进程来完成对同一个文件的读写。例如让父进程写文件的前半部分,子进程来写文件的后半部分,因为两个进程间是可以并发执行的,所以将会节约一部分时间,提高执行的效率。那么怎样才能实现这个功能?

我们以文件IO为例,边讲述如何实现的同时,也给大家说下为什么这样写的原因,希望能给大家得到些启发。

首先来看下用文件IO函数实现拷贝文件的程序:

#include <sys/types.h>
        #include <sys/stat.h>
        #include <fcntl.h>
        #include <stdio.h>
        #define maxsize 256
        int main(int argc,char *argv[])
        {
                if(argc!=3)                //如果命令格式不正确
                {
                        printf("command error!/n");
                        return -1;
                }

        int fd1,fd2;
                if ((fd1= open(argv[1],O_RDONLY))< 0)
                {
                        perror("error");
                        return -1;
                }
                if ((fd2 = open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0644))< 0)
                {
                        perror("error");
                        return -1;
                }
                char s[maxsize ];
                int t=0;
                while ((t=read(fd1,s,maxsize ))==maxsize )
                {
                        write(fd2,s,t);
                }
                write(fd2,s,t);
                close(fd1);
                close(fd2);
                return 0;
        }

这样就实现了文件的拷贝。那么在我们学习完fork函数之后是不是只要父进程和子进程分别写一部分就可以了?

if((src=open(argv[1],O_RDONLY))<0)
        {
                ……
        }
        if((des=open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0644))<0)
        {
                ……
        }
        len=lseek(src,0,SEEK_END);
        int pid;
        if((pid=fork())<0)
        {
                fprintf(stderr,"fork error!:%s/n",strerror(errno));
                return -1;
        }
        else if(pid ==0)
        {
                lseek(src,len/2,SEEK_SET);
                lseek(des,len/2,SEEK_SET);
                while((n=read(src,buf,sizeof(buf)))!=0)
                {
                        write(des,buf,n);
                }
                exit(0);
        }
        else
        {
                lseek(src,0,SEEK_SET);
                lseek(des,0,SEEK_SET);
                while((n=read(src,buf,sizeof(buf)))!=0)
                {
                        write(des,buf,n);
                        if(lseek(src,0,SEEK_CUR) > len/2)
                        break;
                }
                wait(NULL);
                exit(0);
        }

是不是只要这样写就可以实现功能?实践证明这样写不行的,那么为什么这样写不可以呢?

子进程和父进程继续执行fork之后的指令。子进程是父进程的复制品。子进程获得父进程数据空间、堆栈的复制品。注意,这是子进程所拥有的拷贝,父、子进程并不共享这些存储空间部分。那么跟本例相关的一条fork特性就是由父进程打开的文件描述符也被复制到子程序中。父、子进程的每个相同的打开描述符共享一个文件表项。

在unix高级环境编程中有这样一幅图

这种共享文件的方式使父、子进程对同一个文件使用了一个文件位移量。当父进程是其标准输出重新定向,那么子进程写到该标准输出时,它将更新与父进程共享的该文件的位移量。当程序中,父、子进程写到同一个描述符文件,因为没有任何形式的同步,因为它们的输出都混在一起,所以复制后的文件就是错的。那么为了解决该问题,我们应该对所写的程序加以改进。

if((src=open(argv[1],O_RDONLY))<0)
        {
                ……
        }
        if((des=open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0644))<0)
        {
                ……
        }
        len=lseek(src,0,SEEK_END);
        ftruncate(des,len);//创建空洞文件
        printf("len=%ld/n",len);
        int pid;
        if((pid=fork())<0)
        {
                ……
        }
        else if(pid ==0)
        {
                close(src);
                close(des);
                if((src=open(argv[1],O_RDONLY))<0)
                {
                        fprintf(stderr,"open %s failed!:%s/n",argv[1],strerror(errno));
                        return -1;
                }
                if((des=open(argv[2],O_WRONLY))<0)
                {
                        fprintf(stderr,"open %s failed!:%s/n",argv[2],strerror(errno));
                        return -1;
                }
                lseek(src,len/2,SEEK_SET);
                lseek(des,len/2,SEEK_SET);
                while((n=read(src,buf,sizeof(buf)))!=0)
                {
                        write(des,buf,n);
                }
                close(src);
                close(des);
                exit(0);
        }
        else
        {
                lseek(src,0,SEEK_SET);
                lseek(des,0,SEEK_SET);
                while((n=read(src,buf,sizeof(buf)))!=0)
                {
                        write(des,buf,n);
                        if(lseek(src,0,SEEK_CUR) > len/2)
                        break;
                }
                wait(NULL);
                close(src);
                close(des);
                exit(0);
        }

这样父、子进程就不共享同一个文件位移量,虽然打开的是同一个文件,写的也是同一个文件,但是再实际操作中,就不会让父子进程使用同一张文件表了。

 

如果您喜欢这篇文章,可以加华清远见老师为好友,单击以下链接即可:

 
http://student.csdn.net/invite.php?u=45153&c=8af704eb3cd8e773
 

(作者:华清远见嵌入式培训中心   www.embedu.org    www.farsight.com.cn  )

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 公司报销发票纸质的丢了怎么办 在京东上买的小天才手表坏了怎么办 美亚买东西过几天降价了怎么办 天猫买东西退款后又不想退了怎么办 自己写错了地址快递被签收了怎么办 在天猫购买东西不发货怎么办 在天猫买了东西不给我发货怎么办 天猫退货卖家收到货不退款怎么办 唯品会的账号找不回来了怎么办 从网上买的沙发物流超级慢怎么办 三星c5手机玩王者荣耀卡怎么办 买手机送话费的卡不想用了怎么办 到银行存钱被骗买保险了怎么办 去银行存钱被骗买了保险怎么办 京东申请退款后卖家又发货了怎么办 苹果6s没有4g网怎么办 花呗分期付款买手机额度不够怎么办 手机天猫不支持购买淘宝商品怎么办 天猫国际购买商品狠盾怎么办 在微信上微拍堂买东西被骗了怎么办 京东自营买到返修手机怎么办? 7p弯了怎么办能修复吗 农商银行app登录密码忘了怎么办 网址上的重庆时时彩不能提现怎么办 天天中彩票自己账户登录不了怎么办 天猫上卖王者荣耀的兑换码是怎么办 身份证借别人开淘宝永久封店怎么办 天猫店铺被扣12分怎么办 天猫法人变更之前的天猫贷款怎么办 在日本旅游遇到精日导游怎么办 银行资金交易异常卡被冻结怎么办 如果淘宝被盗了店铺乱上东西怎么办 快递不送货直接代售点签收怎么办 淘宝快递没收到却显示已签收怎么办 支付宝余额未满16受限怎么办 未满16岁支付宝余额受限怎么办 手机天猫购物买的数量大怎么办 扣扣游戏领礼包出现账号异常怎么办 美容院转让给别人客人要退钱怎么办 卖家毁约中介费担保费怎么办 天猫买东西店家不开增值税票怎么办