Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c stdout to stdin realtime

Tags:

c

linux

io

pipe

I have make two programs one of them named generator which print some text every second

int main(int argc, char** argv) {

    for(int i = 0; i < 10 ; i++) {
         printf("something\n");
         sleep(1);
    }

  return (EXIT_SUCCESS);
}

then a have a second program call it consumer for now, which should read from a standart input add to it some other text and reprint it. Let it look like this :

 int main(int argc, char** argv) {


   char line[BUFSIZ];

   while(scanf("%s",line) != -1){
       printf("you entered %s \n",line);
   }

    return (EXIT_SUCCESS);
}

when i compile them and try to run only a generator like ./generator it works as I expected. every second something is print to console. but when I try to run them both like ./generator | ./consumer it did not work as i expected. I wait 10 second and after that a get 10 lines of you entered something i want to print "you entered something" every second.

Can you explain me why this is so, or even better tel me how to achieve expected behavior ?.

like image 355
Domino Hýll Avatar asked Nov 04 '16 18:11

Domino Hýll


3 Answers

C I/Os are buffered. When using terminal I/Os, buffering discipline is line buffered so content is flushed to output when \n is sent. When you use pipes, buffering discipline is full buffered so that content is flushed only when the buffer is full (whatever the content is).

You can either:

  1. flush(stdout) every time you need the data to be really written out,
  2. change the buffer discipline by a call to setvbuf prior to any write.
like image 184
Jean-Baptiste Yunès Avatar answered Sep 30 '22 02:09

Jean-Baptiste Yunès


The output from your printf is being buffered, and only coming out when the buffer is full. You can call setbuf() in the consumer (once at the beginning) with NULL as the 2nd argument, to set the buffer size on stdout to NULL.

#include <stdio.h>
setbuf( stdout, NULL );

This will cause output written to stdout (i.e. your printf) to come out immediately. Alternatively you could write to stderr, which by default has a NULL buffer size. (Or, as another alternative, you can call fflush on stdout each time you want to flush the buffer contents out to the terminal).

like image 32
Daniel Goldfarb Avatar answered Sep 30 '22 02:09

Daniel Goldfarb


Output is buffered, so the stdio library waits until it has a bunch of data, typically 4 kilobytes, and then outputs it at once.

Just add a call to fflush whenever you want the output to actually be output:

fflush(stdout);

It works differently when the output is sent directly to the terminal. The standard output is then line buffered, so the buffer is flushed after each end-of-line character.

like image 22
Thomas Padron-McCarthy Avatar answered Sep 30 '22 01:09

Thomas Padron-McCarthy