如何實現多進程寫一個文件


轉載: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!\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高級環境編程中有這樣一幅圖

 

這種共享文件的方式使父、子進程對同一個文件使用了一個文件位移量。當父進程是其標准輸出重新定向,那么子進程寫到該標准輸出時,它將更新與父進程共享的該文件的位移量。當程序中,父、子進程寫到同一個描述符文件,因為沒有任何形式的同步,因為它們的輸出都混在一起,所以復制后的文件就是錯的。那么為了解決該問題,我們應該對所寫的程序加以改進。

 

 

#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\n"); 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\n"); exit(0); } len = lseek(src, 0, SEEK_END); //創建空洞文件
 ftruncate(dst,len); pid = fork(); if (-1 == pid) { printf("fork error\n"); 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; }

 

這樣父、子進程就不共享同一個文件位移量,雖然打開的是同一個文件,寫的也是同一個文件,但是再實際操作中,就不會讓父子進程使用同一張文件表了。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM