Is it alright for multiple processes to access (write) to the same file at the same time? Using the following code, it seems to work, but I have my doubts.
Use case in the instance is an executable that gets called every time an email is received and logs it’s output to a central file.
if (freopen(console_logfile, "a+", stdout) == NULL || freopen(error_logfile, "a+", stderr) == NULL) {
perror("freopen");
}
printf("Hello World!");
This is running on CentOS and compiled as C.
Using the C standard IO facility introduces a new layer of complexity; the file is modified solely via
write(2)-family of system calls (or memory mappings, but that’s not used in this case) — the C standard IO wrappers may postpone writing to the file for a while and may not submit complete requests in one system call.The
write(2)call itself should behave well:Thus your underlying
write(2)calls will behave properly.For the higher-level C standard IO streams, you’ll also need to take care of the buffering. The
setvbuf(3)function can be used to request unbuffered output, line-buffered output, or block-buffered output. The default behavior changes from stream to stream — if standard output and standard error are writing to the terminal, then they are line-buffered and unbuffered by default. Otherwise, block-buffering is the default.You might wish to manually select line-buffered if your data is naturally line-oriented, to prevent interleaved data. If your data is not line-oriented, you might wish to use un-buffered or leave it block-buffered but manually flush the data whenever you’ve accumulated a single “unit” of output.
If you are writing more than
BUFSIZbytes at a time, your writes might become interleaved. Thesetvbuf(3)function can help prevent the interleaving.It might be premature to talk about performance, but line-buffering is going to be slower than block buffering. If you’re logging near the speed of the disk, you might wish to take another approach entirely to ensure your writes aren’t interleaved.