0

I am trying to read specific lines from a file using a parent process to read one line and a child process to read some other line. The simple text file has as contents: "This is line one\n", This is line two\n", etc.

However, I find that when I execute my program multiple times, my child does not always print the line from my file. The printf("Entering child\n") does always get executed, indicating that I am able to enter the child process fine.

Why does this work only sometimes?

int main() {
FILE* fptr = fopen("my_text.txt","r");

int stat;
pid_t pid;
int count = 0;
if(fptr != NULL) {
    char line[256];
    fflush(stdout);
    if((pid = fork()) < 0) {
        fprintf(stderr, "fork error: %s\n",strerror(errno));
    }
    else if(pid == 0) {
        printf("entering child\n");
        int lineNumber = 2; // read the second line
        while (fgets(line, sizeof(line), fptr) != NULL) { // loop until we get to desired line
            if (count == lineNumber) {

                printf("CHILD read: %s", line);

                fflush(stdout);
                rewind(fptr);
                break;
            } else {
                count++;
            }
        }
        exit(0); // exit child process

    } else { // parent process

        int lineNumber = 1; 
        while (fgets(line, sizeof(line), fptr) != NULL) { // loop until desired line
            if (count == lineNumber) {
                printf("PARENT read: %s", line);
                fflush(stdout);  
                rewind(fptr);
                break;
            } else {
                count++;
            }
        }
        wait(&stat); // reap the child process
    }
    fclose(fptr);
} else {
    printf("File Does not exist\n");
    exit(0);
}

return 0; }   

From the above code, I sometimes print "This is line two" (from parent) and "This is line three" (from child), or sometimes only "This is line two". The goal is to get both to print.

mtruong1999
  • 129
  • 1
  • 10
  • 1
    First remember that your line-counting is zero-based, so `lineNumber == 2` means you will print the third line. Secondly, when you find your line, you rewind the file pointer, but you don't reset the counter. Is that supposed to happen? Also, you print without a newline, is that by design? – Some programmer dude Dec 01 '19 at 19:40
  • Doesn't each process get its own copy of counter? So counter in one will still be zero if the counter in the other process is changed. And I print without newline because I find that fgets also gets the \n character from my textfile, so if I add a newline to my print I will end up having two newlines. – mtruong1999 Dec 01 '19 at 19:55
  • Why do you even `rewind` the file when you're `break` out of the loop anyway? – Some programmer dude Dec 01 '19 at 20:00
  • you might want to look into `flock` and `fileno`. – Antti Haapala -- Слава Україні Dec 01 '19 at 20:05
  • OT: regarding: `printf("File Does not exist\n");` Error messages should be output to `stderr` not `stdout`. When the error indication comes from a C library function, should also output to `stderr` the text reason the system thinks the error occurred. The function `perror()` is made for this purpose – user3629249 Dec 02 '19 at 02:21
  • OT: regarding: `printf("File Does not exist\n"); exit(0);` The returned value of 0 from function: `main()` (typically) indicates success, Suggest using: `exit( EXIT_FAILURE );` where both `exit()` and `EXIT_FAILURE` are exposed via the header file: `stdlib.h` – user3629249 Dec 02 '19 at 02:28

1 Answers1

4

The two processes share the open file description, which means that they both share the file offset and therefore you have a race condition because they read the file concurrently. There are two ways obvious to fix:

  • use some IPC mechanism for synchronization, or file description locks - see for example flock.
  • open the file in each process after the fork.

Other advanced methods would e.g. be to read the file with pread, or mmap it before or after the fork...