Search code examples
clinuxipcstdoutstdin

popen not working as expected


I have a program where I need to communicate with another program on its standard input and output. I can use a pipe to send it input and redirect its output to a specified file to be read when it is done, and that works fine. I am not using pipe and dup2 because I would like my program to at least somewhat work on windows as well as linux.

My issue is that I want to use the pipes to stream data.

I tried the following snippet:

#include <stdio.h>

int main()
{
    while (!feof(stdin)) {
        int x;
        scanf("%d", &x);
        printf("%x ", x);
        fflush(0);
    }

    return 0;
}

in conjunction with:

#include <unistd.h>
#include <stdio.h>

int main()
{
        int x;
    FILE *p = popen("./test > tmp.datafile", "w");
    FILE *f = fopen("tmp.datafile", "r");

    for (int i = 0; i < 100; ++i) {
        fprintf(p, "%d", i);

        sleep(1);
        x = fgetc(f);
        printf("%c ", x);
        fflush(0);
    }

    fclose(f);
    pclose(p);

    return 0;
}

However no matter what I do, I just keep getting nulls out of the file. I suspect that perhaps there are concurrency issues, in that I try to read the file before the test executable finishes flushing it, however I am not sure how to fix this.

Is there a better way to communicate with a program via standard streams in c?


Solution

  • fgetc() won't read past EOF once EOF has been reached — which may happen on the very first read. Doing something like

    if(feof(f)) {
        clearerr(f);
        sleep(1);
    } else {
        printf("%c ", x);
    }
    

    should sort-of solve the issue with a busy loop.

    A better idea would be to wait for the file to change once EOF has been reached, but that would require system-specific calls.

    Beware of another race condition: fopen may happen before the file has been created by the command started via popen.

    while(!(f = fopen(..., "r"))
        sleep(1);
    

    It's another busy loop and overall not a good solution that should only be used if dup2() is not available.