0

I'm trying to communicate two processes via Named pipes but I'm having problems with the reader process. The idea is that the consumer reads several messages that the producer writes into the pipe in random periods. Since these periods can be long, the consumer should block in the read operation until the producer has written the message into the pipe.

This is the code that I have now.

FILE* result_pipe_stream;
...
result_pipe_stream = fopen(result_pipe , "r");
...

string read_result_from_pipe(){
    if (result_pipe_stream == NULL){
        return NULL;
    }
    char buf[BUFSIZ];
    std::stringstream oss;
    while (1) {
        if( fgets (buf, BUFSIZ, result_pipe_stream) != NULL ) {
            int buflen = strlen(buf);
            if (buflen >0){
                if (buf[buflen-1] == '\n'){
                        buf[buflen-1] = '\0';
                        oss << buf;
                        return oss.str();
                } else {
                    oss << buf;
                }
            }
        } else {
            // Necessary to avoid that fgets return NULL after closing the pipe for the first time.
            clearerr(result_pipe_stream);
        } 
    }   
}

The first time the consumer reads from the pipe, the method works properly. It awaits until the writer sends a message and returns the value. However, from that point on, when the method is called again the fgets returns NULL until the writer adds the new message.

What is missing for the consumer to block after the second read?

The producers is a Java application writing the pipe like this

try {
   OutputStream output = new FileOutputStream(writePipe, true);
   output.write(taskCMD.getBytes());
   output.flush();
} catch (Exception e)  {
   e.printStackTrace();
} finally {
   if (output != null) {
       output.close();
   }
}
Francesc Lordan
  • 519
  • 4
  • 24
  • So the producer closes the write end of the pipe after each write? Then the consumer needs to close and reopen the read end after getting an EOF. Or `poll()` the underlying descriptor until it's readable. That's probably better, actually. – Shawn Sep 07 '22 at 17:50
  • (if you're sending discrete messages I'd use datagram unix domain sockets instead) – Shawn Sep 07 '22 at 17:51
  • I tried that. I was closing and opening the file right after the clearerr invocation. It behaves as expected, but from time to time, a message is lost. Looks like fgets returns NULL; then Java writes the message and then the pipe is closed and reopen with no content :S – Francesc Lordan Sep 07 '22 at 18:00
  • Yeah, there's a race condition. I realized that a few minutes later and went back and added a suggestion to use `poll()` instead. – Shawn Sep 07 '22 at 18:03
  • Another possibility to explore: don't close the write end in the producer and make sure there's some way to tell messages apart (like a special character between them that doesn't appear elsewhere) – Shawn Sep 07 '22 at 18:06
  • I tried the `poll()` option. Same behaviour: it's not blocking and returns immediately with content no content – Francesc Lordan Sep 08 '22 at 06:51
  • I ended up keeping the pipe open in the Java code – Francesc Lordan Sep 08 '22 at 08:47

0 Answers0