zoukankan      html  css  js  c++  java
  • 如何实现多进程写一个文件

    转载:http://www.eefocus.com/ayayayaya/blog/10-07/193194_0d80b.html

    在我们学习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! ");
                            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 ",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高级环境编程中有这样一幅图

     

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

     

     

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <strings.h>
    
    #define BUFFSIZE 30
    
    //copy file
    
    
    int main(int argc, char* argv[])
    {
        int src;
        int dst;
        int ret;
        char buff[BUFFSIZE];
        pid_t pid;
        int len;
        int n;
            
    
        if (argc != 3)
        {
            printf("have no enough parameter
    ");
            exit(0);
        }
    
        src = open(argv[1], O_RDONLY);
        dst = open(argv[2], O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
    
        if(-1==src || -1==dst)
        {
            printf("open file error
    ");
            exit(0);
        }
        
        len = lseek(src, 0, SEEK_END);
        //创建空洞文件
        ftruncate(dst,len);
    
        pid = fork();
        if (-1 == pid)
        {
            printf("fork error
    ");
            exit(0);
        }
        else if (0 == pid)
        {
            close( src );
            close( dst );
    
            src = open(argv[1], O_RDONLY);
            dst = open(argv[2], O_WRONLY);
    
            lseek(src,len/2,SEEK_SET);
            lseek(dst,len/2,SEEK_SET);
    
            while( (n = read(src, buff, BUFFSIZE)) > 0)
            {
                write(dst, buff, n);
            }
            
    
            close( src );
            close( dst );
            exit( 0 );
    
        }
        else
        {
            lseek(src, 0, SEEK_SET);
            lseek(dst, 0, SEEK_SET);
        
            while( (n = read(src, buff, BUFFSIZE)) > 0)
            {
                write(dst, buff, n);
                if ( (n = lseek(src, 0, SEEK_CUR)) > len/2 )
                {
                    break;
                }
            }
            
        }
    
        wait(NULL);
    
        
        
    
        close( src );
        close( dst );
        
    
        return 0;
    }

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

     

  • 相关阅读:
    HDU4611+数学
    HDU4612+Tarjan缩点+BFS求树的直径
    HDU4602+推导公式
    HDU4607+BFS
    HDU1353+贪心
    HDU4545+LCS
    HDU4548+素数
    HDU4539+状态压缩DP
    HDU2110+母函数
    HDU1569+最大点权集
  • 原文地址:https://www.cnblogs.com/zhangxuan/p/6323129.html
Copyright © 2011-2022 走看看