2010-12-01 45 views
3

此代碼似乎工作,但我有沒有正確使用InterlockedIncrement函數? m_count的正確內存對齊是我最關心的問題。假設我們在一個x86-64系統上編譯一個64位應用程序(如果有的話)。順便說一句,對於我的實際目的,我不能將m_count聲明爲volatile,然後使用InterlockedIncrement(& m_count);但它必須是堆中數據的指針。如何從堆中爲InterlockedIncrement函數分配正確的內存對齊方式?

#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; 
}; 
+2

爲什麼它必須在堆上?因爲你想使用_aligned_malloc?無論如何,_aligned_malloc是一個編譯器擴展,因此您不妨使用GCC和MSVC編譯器上可用的#pragma pack指令來實現對齊要求。 GCC和MSVC上的默認編譯指南已經滿足了互鎖操作的基本對齊要求。所以你真的好像想到了這個問題。 – 2010-12-01 11:42:23

回答

5

堆分配器已將返回的地址與本機平臺字大小對齊。 x86爲4個字節,x64爲8個字節。您正在使用長的,32位在任一MSVC平臺上。無需跳過_aligned_malloc()箍。

3

這是一個平臺架構細節,但您需要記住,除了對齊之外,還有更多的原子操作。平臺ABI通常會確保默認的基本數據類型對齊,以便任何操作(包括原子)都能工作。 malloc()不應該返回給你一個未對齊的指針,即使你要求單個字節。

雖然,除此之外,特別注意http://en.wikipedia.org/wiki/False_sharing - 意思是超出需要對齊的需要(通常爲sizeof(long)),您還必須確保在同一緩存行中只託管一個原子訪問的變量。

如果您打算使用/允許這些計數器的數組,那麼這一點尤其重要。

微軟的編譯器使用__declspec(align(value))來指示編譯器保證特定的結構對齊。正如其他人提到的,似乎沒有特別需要這樣的數據結構/類被堆分配,但我不知道是否需要pimpl來做其他事情。

1

對於您的用例最容易做的事情是通過繼承使用侵入式引用計數,消除了這種需求。

但是,如果您絕望,只需查看MSVC的shared_ptr實現。

typename aligned_storage<sizeof(_Ty), 
     alignment_of<_Ty>::value>::type _Storage; 
    }; 
    _Ty *_Getptr() const { // get pointer 
     return ((_Ty *)&_Storage); 
    } 

那個C-cast是相當討厭的。不過,這表明這個對象肯定會有正確的對齊,利用類型特徵。