Is a successful call to write(2) atomic?

Ronald F. Guilmette rfg at tristatelogic.com
Wed Jun 16 22:39:57 UTC 2021


In message <7801a6e8-2428-619e-5722-7317841595a1 at qeng-ho.org>, 
Arthur Chance <freebsd at qeng-ho.org> wrote:

>>From Posix documentation on write(2):
>
>Atomic/non-atomic: A write is atomic if the whole amount written in one
>operation is not interleaved with data from any other process.
>
>However, only two cases are guaranteed to be atomic:
>
>1) writes to a pipe/FIFO of <= PIPE_BUF bytes
>
>See the beginning of the Rationale section of
>
>https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html
>
>2) writes to a regular file from different pthreads *within the same process*

Ohhhhhhh!  Thank you for fishing all of this info out for me!  It certainly
puts a different complexion on the whole matter.

>Apart from the first case there is no requirement for atomic writes in
>Posix when multiple processes are involved.

Yes.  Got it.  Thanks.

And to make matters even slightly MORE annoying, here on my FreeBSD 12.2
system it seems that PIPE_BUF is defined in <sys/syslimits.h> to what
I consider to be an unfortunately low number... obviously a relic of
ancient times, i.e. 512.  (Some of my output lines are quite likely to
exceed this.)

The only reason I mention that is because I've just tried changing my
code so that the FD (#1) gets O_APPEND set on it at startup time and
then the calls to write() are wrapped in calls to flock() just as
John Levine and others suggested.  Result?  Output is still garbled.

Thus, I am off to pursue plan C, i.e. passing completed lines up from
the "worker bee" children to the master/parent process which will then
be responsible for doing all of the actual writing of lines to FD #1.

I had hoped that maybe I could do this simply and just have a single
common "up" pipe to carry completed lines from the children to the
parent, but because POSIX only assures me that lines up to 512 bytes
may be written atomically to that pipe, and because some of my output
lines may exceed that, I guess that I have to use separate "up"
pipes for -each- child process (and then make calls to select(), within
the parent, as was suggested here, and having the master read from
whichever ones of those have data available at any given point in time).

Anyway, I'll be trying that next.

The one really odd thing about all of this is that I already have, and
have had, for a long time now, *many* programs that I've built and that
I have been using, also for a long time, that follow this same general
model, i.e. a parent a a lot of "worker bee" child processes where each
of the children, after completing a work item, does itself write a single
line of output, and *those* programs have all seemed to work flawlessly
(i.e. no output garbling) over a long period of time.... HOWEVER they
are all using the stdio functions to write to stdout, rather than
calling write() directly to write to FD #1.

I only changed *this* one program of mine to call write() directly because
I've been perpetually worried that having a lot of independend child
processes all writing to their (shared) stdout in a totally uncoordinated
and asynchronous manner was just asking for trouble.  But now, instead
of -avoiding- trouble (by switching from calling stdio functions to
making direct calls to write()) I seem to have possibly created trouble
for myself instead!

Obviously, I have no good explanation for this, but I do think that before
I try anything else I may just try changing the child processes in this
program so that the child processes call fwrite() rather than write()...
just to see if that makes any difference.

I can't see any clear reason why using fwrite() rather than write() could,
would, or should help, but what do I know?

Meanwhile, later that same day...

OK, so I tried swapping out calls to write() to call to fwrite()...

Result:  Some output lines still garbled.

So I'm either getting bitten by the non-atomicity of {f}writes or else I've
just got a loose pointer in my code somplace.

I will be checking both theories and following up here with more results,
when and as I have them.

Meanwhile, my thanks to everyone who has chimed in.


Regards,
rfg


More information about the freebsd-questions mailing list