2016-01-21 73 views
2

我在使用fseek()和fork()(實際上使用XUbuntu 15.10)時遇到問題。 我必須編寫一個程序,它從文件(「file1」)中讀取一系列數字(不同行),並報告與特定字符串匹配的行數,作爲參數傳遞。
我稱之爲「nf」的程序必須被調用如下(./nf number_of_processes file1 match_string)。
程序應該創建number_of_processes子進程(使用fork()),並且它們中的每個應該處理文件的單個部分(即,如果number_of_processes是5並且該文件有15行,則每個子進程應該處理15/5 =文件的3行)。
子進程應該將結果報告給父親,父親將打印文件中發現的事件數量。

現在,問題是:我使用fseek編寫程序(每個子進程在文件內部找到它的正確位置,並開始分析它的長度爲單個部分),但有時它似乎工作,而其他一些它打印出不正確的結果,就像是以不正確的方式讀取文件(多次讀取文件或讀取垃圾而不是數字字符串)...
您知道爲什麼會發生這種情況?
非常感謝。

的文件是以下物質:
file1的:fseek()帶叉子()不能正常工作

1224332 
1224332 
4363666 
4363666 
1224332 
5445774 
2145515 
1224332 
2145515 
1111111 
2145515 
9789899 
2344444 
6520031 
4363666 

nf.c:

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

#define NBYTES 8 

int FileLenght(FILE *fp) { 
    int cnt=0; 
    char c; 

    while((c=getc(fp))!=EOF) { 
     if(c=='\n') { 
      cnt++; 
     } 
    } 

    rewind(fp); 

    return cnt; 
} 

int main (int argc, char *argv[]) { 
    int num,vlen=0,i,j=0,cnt=0; 
    pid_t *pid; 
    int status,sum=0; 
    FILE *fp; 
    char string[NBYTES+1]; 

    if(argc!=4) { 
     printf("Error using program.\n"); 
     exit(EXIT_FAILURE); 
    } 

    num=atoi(argv[1]); 

    fp=fopen(argv[2],"r+"); 

    if(!fp) { 
     fprintf(stderr,"Error opening file.\n"); 
     exit(EXIT_FAILURE); 
    } 

    vlen=FileLenght(fp); 

    pid=malloc(num*sizeof(pid_t)); 

    for(i=0;i<num;i++) { 
     if(!(pid[i]=fork())) { 
      fseek(fp,i*(NBYTES)*(vlen/num),SEEK_SET); 
      while(j<vlen/num) { 
       fscanf(fp,"%s",string); 
       printf("Process %d reading from file: %s\n",getpid(),string); 
       if(!strcmp(string,argv[3])) { 
        cnt++; 
       } 
       j++; 
       printf("(%d-%d) %d %s=%s\n",getpid(),getppid(),j,string,argv[3]); 
      } 
      fclose(fp); 
      exit(cnt); 
     } 
    } 

    fseek(fp,vlen*NBYTES,SEEK_SET); 

    for(i=0;i<num;i++) { 
     waitpid(pid[i],&status,0); 
     sum+=WEXITSTATUS(status); 
    } 

    printf("\nTotal found: %d\n",sum); 

    fclose(fp); 
    free(pid); 

    return 0; 
} 

輸出(正確的計數應爲4,而不是5):

$ ./nf 5 file1 1224332 
Process 18592 reading from file: 1224332 
Process 18593 reading from file: 4363666 
(18593-18591) 1 4363666=1224332 
Process 18593 reading from file: 4363666 
(18593-18591) 2 4363666=1224332 
(18592-18591) 1 1224332=1224332 
Process 18592 reading from file: 1224332 
(18592-18591) 2 1224332=1224332 
Process 18594 reading from file: 1224332 
Process 18596 reading from file: ���ҿ� 
(18594-18591) 1 1224332=1224332 
Process 18595 reading from file: 2145515 
(18595-18591) 1 2145515=1224332 
Process 18595 reading from file: 1224332 
(18595-18591) 2 1224332=1224332 
(18596-18591) 1 ���ҿ�=1224332 
Process 18596 reading from file: ���ҿ� 
Process 18594 reading from file: 1224332 
(18594-18591) 2 1224332=1224332 
(18596-18591) 2 ���ҿ�=1224332 

Total found: 5 
+0

獲取文件大小的方法比逐字節讀取每個字節更容易(也更快)。例如,通過[尋求](http://en.cppreference.com/w/c/io/fseek)並獲取[當前位置](http://en.cppreference.com/w/c/) IO/FTELL)。 –

+0

感謝您的建議!這一定會讓程序變得更好更輕鬆!然而,它並沒有解決這個問題,我認爲這個問題與使用fork()和fseek()有關......奇怪的是...有時它有效,有時候不行! – ProgProb

回答

3

當進程之間共享文件描述符時作爲fork()的結果,文件描述符的所有屬性在包括當前偏移量的拷貝之間共享。因此,程序中的所有子進程都試圖同時尋找並從同一個文件描述符中讀取數據,從而導致各種意想不到的結果。

要解決此問題,您需要延遲打開文件直到您已經分叉爲止,或者在分叉後爲文件描述符創建每個子進程的獨立副本。

+0

非常感謝!我在分叉之後移動了文件,並解決了問題! – ProgProb

0

也許這是由指針fp引起的。因爲每次創建子線程時,子進程都使用相同的fp,所以有時會打印4個,有時會打印5個,有時會打印3個,也是2個。