Is a successful call to write(2) atomic?

Paul Procacci pprocacci at gmail.com
Tue Jun 15 06:55:29 UTC 2021


On Tue, Jun 15, 2021 at 2:11 AM Ronald F. Guilmette <rfg at tristatelogic.com>
wrote:

>
> Assume that a given program, "example", forks a child process (or perhaps
> many such) and then each of these processes tries, in a manner that is
> entirely non-sychronized with any of the others, to write blocks of data
> using calls to write(2) to file descriptor 1.
>
> Assume further that "example" is run from the command line as follows:
>
>      example > ordinary-disk-file
>
> Lastly asume that the return value for all calls to write() is diligently
> checked to insure that it is never either -1 or a short write count,
> and that if it ever, is, "example" will exit with a non-zero exit status
> (and assume also that otherwise it will exit with a zero exit status).
>
> Question:  Assuming that "example" runs and exits with a zero status (thus
> indicating that all calls to write() completed successfully and none
> returned
> a short write count) then might it ever be the case that some single chunk
> of data that was successfully written to "ordinary-disk-file" by a single
> call to write() might be split into two or more parts in the output file,
> with chunks of data that were written by other processes in the same family
> possibly being interleaved between parts of that one chunk in the output
> file?
>
>
I had a long response, but decided to shorten it....I hope you don't mind.

The only time atomicity is guaranteed is for pipes when the write(2) size
fits in PIPE_BUF (512 bytes on my version of FreeBSD).
Otherwise, it depends is really the best answer as it depends on the file
system.
Sometimes filesystems like ext4 require O_DIRECT to be set, in order to
avoid the garbled text as you've mentioned, and even then it's limited to
the number of bytes written.

A suggestion; the way I've done something similar in the past.....

Parent Process - Orchestrator - creates pipes handing one end of the pipe
to each child.
Child Process - do'ers - write whatever it intends on writing to the pipe
the parent is waiting for data on.
Parent process then grabs the data the child wrote, and in turn writes it
to stdout (or whatever file descriptor you intend).

This method, a bit more involved, ensures one writer to a file descriptor,
is portable, and you can rest easy about it working on whatever latest and
greatest file system someone decides to make.

That's always been my understanding anyways, and I am open to being
corrected.

~Paul


-- 
__________________

:(){ :|:& };:


More information about the freebsd-questions mailing list