LambdaBeta LambdaBeta - 6 days ago 5
Linux Question

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?

Answer

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.