memory fences/barriers in C++: does boost or other libraries have them?
I am reading these days about memory fences and barriers as a way to synchronize multithreaded code and avoid code reordering.
I usually d开发者_如何学JAVAevelop in C++ under Linux OS and I use boost
libs massively but I am not able to find any class related to it. Do you know if memory barrier of fences are present in boost or if there is a way to achieve the same concept? If not what good library can I have a look to?
There are no low-level memory barriers in boost yet, but there is a proposed boost.atomic library that provides them.
Compilers provide their own either as intrinsics or library functions, such as gcc's __sync_synchronize()
or _mm_mfence()
for Visual Studio.
The C++0x library provides atomic operations including memory fences in the form of std::atomic_thread_fence
. Though gcc has supplied various forms of the C++0x atomics since V4.4, neither V4.4 or V4.5 include this form of fence. My (commercial) just::thread
library provides a full implementation of C++0x atomics, including fences for g++ 4.3 and 4.4, and Microsoft Visual Studio 2005, 2008 and 2010.
The place where memory barriers are required is when avoiding using kernel synchronisation mechanisms in an SMP environment - usually for performance reasons.
There is an implicit memory barrier in any kernel synchronisation operation (e.g. signalling semaphores, locking and unlocking mutices) and content switching to guard against data coherence hazards.
I have just found myself needing (moderately) portable memory barrier implementations (ARM and x86), and also found the linux source tree to be the best source for this. Linux has SMP variants of the mb()
, rmb()
and wmb()
macros - which on some platforms result in more specific (and possible less costly) barriers than the non-SMP variants.
This doesn't appear to be a concern on x86 and particularly ARM where though where both are implemented the same way.
This is what I've cribbed together from linux header files (suitable for ARMv7 and non-ancient x86/x64 processors)
#if defined(__i386__ ) || defined(__x64__)
#define smp_mb() asm volatile("mfence":::"memory")
#define smp_rmb() asm volatile("lfence":::"memory")
#define smp_wmb() asm volatile("sfence" ::: "memory")
#endif
#if defined(__arm__)
#define dmb() __asm__ __volatile__ ("dmb" : : : "memory")
#define smp_mb() dmb()
#define smp_rmb() dmb()
#define smp_wmb() dmb()
#endif
Naturally, dabbling with memory barriers has the attendant risk that the resulting code is practically impossible to test, and any resulting bugs will be obscure and difficult to reproduce race conditions :/
There is, incidentally, a very good description of memory barriers in the Linux kernel documentation.
There is a boost::barrier
class/concept but it's a bit high level. Speaking of which, why do you need a low level barrier? Synchronization primitives should be enough, shouldn't they? And they should be using memory barriers where necessary, either directly or indirectly through other, lower level primitives.
If you still think you need a low-level implementation, I know of no classes or libraries that implement barriers, but there's some implementation-specific code in the Linux kernel. Search for mb()
, rmb()
or wmb()
in include/asm-{arch}/system.h
.
Now, in 2019, the C++11 fences should be available on nearly every implementation of the C++ standard library. The header ist <atomic>
.
You can issue a fence by calling std::atomic_thread_fence
. In short:
std::atomic_thread_fence(std::memory_order_release);
guarantees that no store operations are moved past the call. (All side effects will be made visible to other threads.)std::atomic_thread_fence(std::memory_order_acquire);
guarantees that no load operations are moved before the call. (All side effects of other threads will be made visible.)
There are more details in the documentation.
精彩评论