Pipe data to thread. Read stuck

Viewed 13

I want to trigger a callback when data is written on a file descriptor. For this I have set up a pipe and a reader thread, which reads the pipe. When it has data, the callback is called with the data.

The problem is that the reader is stuck on the read syscall. Destruction order is as follows:

  1. Close write end of pipe (I expected this to trigger a return from blocking read, but apparently it doesn't)
  2. Wait for reader thread to exit
  3. Restore old file descriptor context (If stdout was redirected to the pipe, it no longer is)
  4. Close read end of pipe
1 Answers

When the write end of the pipe is closed, on the read end, the read() system call returns 0 if it is blocking.
Here is an example program creating a reader thread from a pipe. The main program gets the data from stdin thanks to fgets() and write those data into the pipe. On the other side, the thread reads the pipe and triggers the callback passed as parameter. The thread stops when it gets 0 from the read() of the pipe (meaning that the main thread closed the write side):

#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>

int pfd[2];

void read_cbk(char *data, size_t size)
{
  int rc;

  printf("CBK triggered, %zu bytes: %s", size, data);

}

void *reader(void *p){

  char data[128];
  void (* cbk)(char *data, size_t size) = (void (*)(char *, size_t))p;
  int rc;

  do {

    rc = read(pfd[0], data, sizeof(data));
    switch(rc) {

    case 0: fprintf(stderr, "Thread: rc=0\n");
      break;
    case -1: fprintf(stderr, "Thread: rc=-1, errno=%d\n", errno);
      break;
    default: cbk(data, (size_t)rc);
    }

  } while(rc > 0);

}

int main(){

    pthread_t treader;
    int rc;
    char input[128];
    char *p;

    pipe(pfd);

    pthread_create(&treader, NULL, reader , read_cbk);

    do {

      // fgets() insert terminating \n and \0 in the buffer
      // If EOF (that is to say CTRL-D), fgets() returns NULL
      p = fgets(input, sizeof(input), stdin);
      if (p != NULL) {
        // Send the terminating \0 to the reader to facilitate printf()
        rc = write(pfd[1], input, strlen(p) + 1);
      }

    } while (p);

    close(pfd[1]);

    pthread_join(treader, NULL);

    close(pfd[0]);
}

Example of execution:

$ gcc t.c -o t -lpthread
$ ./t
azerty is not qwerty
CBK triggered, 22 bytes: azerty is not qwerty
string
CBK triggered, 8 bytes: string
# Here I typed CTRL-D to generate an EOF on stdin
Thread: rc=0
Related