tags:

views:

159

answers:

4

I have an application that monitors a high-speed communication link and writes logs to a file (via standard C file IO). The response time to messages that arrive on the link is important, so I knowingly don't fflush the file at each message, because this slows down my response time.

However, in some circumstances my application is terminated "violently" (e.g. by killing the process), and in these cases the last few log messages are not written (even if the communication link has been quiet for some time).

What techniques/strategies can I use to make sure most of my data is flushed, but without giving up speed of response?

Edit: The application runs on Windows

+3  A: 

Using a thread is the standard solution to this. Have your data collection code write data to a thread-safe queue and use a semaphore to signal the writing thread.

However, before you go there, double-check your assertion that fflush() would be slow. Most operating systems have a file system cache. It makes writes very fast, as simple memory-to-memory block copy. The data gets written to disk lazily, your crash won't affect it.

Hans Passant
Thread won't save you when segfault occurs.
Arkadiy
I have to agree with nobugz - are you sure fflush is what slows you down? usually it's sync() that takes time...
Arkadiy
won't this improve performance only for multicore machines?
Eli Bendersky
No, you are only worried about I/O delays. They don't cost cycles.
Hans Passant
+3  A: 

If you are on Unix or Linux, your process would receive some termination signal which you can catch (except SIGKILL) and fflush() in your signal handler.

For signal catching see man sigaction.

EDIT: No idea about Windows.

qrdl
OP sees buffered log messages on exit, so it's a normal termination, not a signal. Also note that calling fflush() from a signal handler is undefined.
fizzer
On normal termination all open fds are flushed and closed, isn't it?
qrdl
OP changed his mind - first version of question said the 'last few log messages were now written' as opposed to 'not written' - which makes quite a difference.
fizzer
sorry, it was a typo :-/
Eli Bendersky
A: 

If your program terminates by calling exit() or returning from main(), the C standard guarantees that open streams are flushed and closed, so no special handling is needed. It sounds from your description like this is what is happening: if your program died due to a signal, you wouldn't see the flush.

I'm having trouble understanding what the problem is exactly.

If it's just that you're trying to find a happy medium between flushing often and the default fully buffered output, then maybe line buffering is what you want:

setvbuf(stream, 0, _IOLBF, 0);
fizzer
+1  A: 

I would suggest an asynchronous write-though. That way you don't need to wait for the write IOP to happen, nor will the OS will delay the IOP. See CreateFile() flags FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED.

You don't need FILE_FLAG_NO_BUFFERING. That's only to skip the OS cache. You would only need it if you are worried about the entire OS dying violently.

MSalters
isn't write through similar to calling fflush() after each write?
Eli Bendersky
fflush means "get it out of the cache now, and don't get back to me until that's done". That's completely at odds with asynchronous writes. An async write call to a file will not wait at all, not for the OS cache nor for the actual disk.
MSalters