【问题标题】:fseek() with fork() not working properlyfseek() 与 fork() 无法正常工作
【发布时间】:2016-01-21 17:13:35
【问题描述】:

我在将 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 编写了程序(每个子进程在文件中找到其正确位置并开始分析它的单个部分的长度),但有时它似乎工作,而其他一些它打印不正确的结果,就像它以不正确的方式读取文件(多次读取或读取垃圾而不是数字字符串)......
你知道为什么会这样吗?
提前非常感谢。

文件如下:
文件1:

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

【问题讨论】:

  • 获取文件大小的方法比逐字节读取文件的每个字节更简单(也更快)。例如通过seeking 到最后并得到the current position
  • 感谢您的建议!这肯定会使程序更好更容易!但是,它并没有解决问题,我认为这与 fork() 和 fseek() 的使用有关……奇怪的是……有时有效,有时无效!

标签: c process fork fseek


【解决方案1】:

当一个文件描述符作为fork()的结果在进程之间共享时,文件描述符的所有属性在副本之间共享,包括当前偏移量。结果,你程序中的所有子进程都试图同时从同一个文件描述符中寻找和读取数据,导致各种意想不到的结果。

要解决这个问题,你需要延迟打开文件直到你已经fork,或者dup() fork 后的文件描述符为每个子进程创建一个独立的副本。

【讨论】:

  • 非常感谢!我在fork后移动了文件打开,这解决了问题!
【解决方案2】:

可能是指针fp造成的。因为每次创建子线程时,子线程都使用同一个fp,所以有时打印4,有时打印5,有时打印3,也打印2。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-13
    • 2015-12-20
    • 2018-02-24
    • 2015-10-27
    • 2016-12-01
    • 1970-01-01
    • 2011-03-07
    • 1970-01-01
    相关资源
    最近更新 更多