How to allocate from heap with the correct memory alignment for InterlockedIncrement function?
This code seems to wo开发者_如何学JAVArk, but have I used the InterlockedIncrement function correctly? The correct memory alignment of m_count is of my primary concern. Assume we're on a x86-64 system and compile a 64-bit application (in case that matters). By the way, for my actual purposes I can't declare m_count as a volatile long and then use InterlockedIncrement(&m_count); but it must be a pointer to data in heap.
#include <Windows.h>
#include <malloc.h>
class ThreadSafeCounter {
public:
ThreadSafeCounter()
{
// Are those arguments for size and alignment correct?
void* placement = _aligned_malloc( sizeof(long), sizeof(long) );
m_count = new (placement) long(0);
}
~ThreadSafeCounter()
{
_aligned_free( const_cast<long*>(m_count) );
}
void AddOne()
{
InterlockedIncrement(m_count);
}
long GetCount()
{
return *m_count;
}
private:
volatile long* m_count;
};
The heap allocator already aligns returned addresses to the native platform word size. 4 bytes for x86, 8 bytes for x64. You are using long, 32-bit on either platform for MSVC. No need to jump through the _aligned_malloc() hoop.
It's a platform architecture detail but you need to keep in mind that there's more to atomic operations than alignment. The platform ABIs usually make sure that primitive data type alignment by default is so that any operation (including atomics) will work. malloc() should never return you a misaligned pointer, not even if you ask for a single byte.
Although, in addition to that, specifically watch out for http://en.wikipedia.org/wiki/False_sharing - meaning beyond the need to have alignment (usually a sizeof(long)
) you also must make sure to host only a single atomically-accessed variable within the same cacheline.
That is particularly important if you plan to use/allow arrays of these counters.
Microsoft's compilers use __declspec(align(value))
for instructing the compiler to guarantee specific structure alignment. As others mentioned, there seems no specific need for such a data structure / class to be heap-allocated, but I can't know if you need pimpl for something else.
The easiest thing to do for your use case is to use intrusive reference counting via inheritance, eliminating this need.
However, if you're desperate, just check out MSVC's implementation of shared_ptr.
typename aligned_storage<sizeof(_Ty),
alignment_of<_Ty>::value>::type _Storage;
};
_Ty *_Getptr() const { // get pointer
return ((_Ty *)&_Storage);
}
That C-cast is quite nasty. However, this suggests to me that this object will most definitely have the correct alignment, utilizing type traits.
精彩评论