tags:

views:

192

answers:

4

Here is the situation : Some process writes lines into a fifo file (created with mkfifo). At some point in my program, I want to read the last line in the fifo, and discard all the others. The procedure may block, only if there is less than one line in the fifo.

I can't come up with a clean way to do this, any ideas ?

EDIT : The writing process will never stop writing lines into the fifo, What I mean by the last line is the last by the time I read the fifo. It is not necessarily followed by a EOF.

+1  A: 

The only way I can think of to do this involves having your program (the one reading) reading all the information in the FIFO -- that is, the read pointer in your program is always at the end of the pipe. When a message is read, you'll add it to an internal list of messages (i.e. a queue or something similar). You'll also maintain a pointer to the last message read.

Reading the last line and discarding all the others, then, is simply the process of following the pointer to the last message and, if desired, clearing the queue.

The problems here are that your internal queue might become large, and that you'll need concurrency control for the queue and last message pointers. I'd have the FIFO reader in its own thread doing nothing but listening to the pipe. When a message comes in, you'll need to lock the queue, add the new message and update the last message pointer, then release the lock. Make sure you process all available incoming messages before releasing the lock. In the thread doing the processing, you should lock the queue to operate on it. Make sure you're locking the queue for no longer than absolutely necessary, or you'll have performance issues.

jfawcett
+3  A: 

If your main concern is that the read will block then open the FIFO as non-blocking. I assume you know what you are looking for in the stream and will simply discard everything before.

You can also use something like select() to be informed when there is something to read off the pipe.

Duck
+2  A: 

If I understood your problem correctly, you have another process that feeds your program with data over the fifo, and new data obsoletes any previously received data, thus you are only interested in the latest data available.

In this case my approach would be - set non-blocking mode for the fifo's descriptor using O_NONBLOCK flag for fcntl() syscall, and use something like this:

while (!exit_condition) {
    bytes = read(fd, wrkbuf, sizeof(wrkbuf));  // error handling omitted
    if (0 == bytes && bytes_to_process > 0) {
        process(wrkbuf, bytes_to_process);
        bytes_to_process = 0;
    } else
        bytes_to_process = bytes;
}
qrdl
thanks, this is what I eventually did ..
Ben