Technically yes, but no on many platforms. First, let us assume that int
is 32 bits (which is pretty common, but not nearly universal).
It is possible that the two words (16 bit parts) of a 32 bit int
will be read or written to separately. On some systems, they will be read separately if the int
isn't aligned properly.
Imagine a system where you can only do 32-bit aligned 32 bit reads and writes (and 16-bit aligned 16 bit reads and writes), and an int
that straddles such a boundary. Initially the int
is zero (ie, 0x00000000
)
One thread writes 0xBAADF00D
to the int
, the other reads it "at the same time".
The writing thread first writes 0xBAAD
to the high word of the int
. The reader thread then reads the entire int
(both high and low) getting 0xBAAD0000
-- which is a state that the int
was never put into on purpose!
The writer thread then writes the low word 0xF00D
.
As noted, on some platforms all 32 bit reads/writes are atomic, so this isn't a concern. There are other concerns, however.
Most lock/unlock code includes instructions to the compiler to prevent reordering across the lock. Without that prevention of reordering, the compiler is free to reorder things so long as it behaves "as-if" in a single threaded context it would have worked that way. So if you read a
then b
in code, the compiler could read b
before it reads a
, so long as it doesn't see an in-thread opportunity for b
to be modified in that interval.
So possibly the code you are reading is using these locks to make sure that the read of the variable happens in the order written in the code.
Other issues are raised in the comments below, but I don't feel competent to address them: cache issues, and visibility.
foo_.a
in a different thread, then yes, it's UB. (§1.10/4 and §1.10/21) C++03 says nothing about concurrency. – Perquisitestd::atomic
if you can and don't worry about it. – PyrotechnicsInterlockedRead
, unfortunately. AFAIK you can useInterlockedCompareExchange(v, 0, 0)
at a slight performance cost, or write your ownInterlockedRead
using compiler assumptions and extensions (like_MemoryBarrier
and the fact that the contract of the function assumes the supplied integer is aligned properly, and ensure the type is such that the platforms Windows run on gives that integer atomic reads). – Pyrotechnicsstd::atomic
's behaviors for your use case. – Pyrotechnics