Reputation: 7873
In the Boost 1.5.1 source under smart_ptr\detail\atomic_count_win32.hpp
is a neat little atomic reference counter boost::detail::atomic_count
.
on line 48, they do a cast I'm curious about:
class atomic_count
{
public:
// ...
operator long() const
{
return static_cast<long const volatile &>( value_ );
}
private:
long value_;
Why is the counter value cast to a-reference-to-a-volatile-constant-long (long const volatile&
)?
Upvotes: 4
Views: 122
Reputation: 182865
On x86 platforms, for aligned values of native width, this is known to be sufficient.
The problem they're trying to avoid is this:
The variable has the hex value 0000FFFF
.
Thread A starts to read the value and gets the 0000xxxx
part.
Thread B increments the value from 0000FFFF
to 00010000
.
Thread A finishes reading the value, getting the xxxx0000
part that it hadn't read yet.
Thread A has now read a value of 00000000
!
This is called word tearing. However, it is known that this doesn't happen for aligned types of native width on x86. So a mere cast through volatile
(which is known to avoid problematic compiler optimizations) is all that is needed.
Note that this is not some general truth. This just happens to be a property of the platform. This isn't portable code.
Upvotes: 1
Reputation: 504293
MSVC provides a now-deprecated extension on volatile
variables, giving them acquire and release semantics (memory ordering guarantees, with respect to multithreaded programming.)
This cast "enables" this extension on the variable, giving it read-acquire semantics (to match any release-writes that may also occur). Again, this is, non-standard. In C++11 code you should use std::atomic<>
.
They need this because boost::shared_ptr
gives guarantees of correctness for shared_ptr<T>
in multithreaded (shared) use; this is their implementation of a lock-free counter.
(Also, this is only half the story: while this extension may provide the needed ordering and visibility guarantees, it does not guarantee atomicity. On Win32 this is guaranteed implicitly by the platforms it runs on: aligned word-sized integer reads and writes are atomic per the platform.)
To nip it in the bud before it starts: without this extension volatile
is not useful for multithreaded programming. Don't even try. This extension is deprecated, so you should really avoid it if you can.
Upvotes: 5