2010-12-01 5 views
3

このコードはうまくいくようですが、InterlockedIncrement関数を正しく使用しましたか? m_countの正しいメモリアラインメントが私の主な関心事です。私たちがx86-64システムを使い、64ビットアプリケーションをコンパイルするとします(問題の場合)。ちなみに私の実際の目的では、m_countを揮発性の長いものとして宣言することはできず、次に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のデフォルトのプラグマパッキングは、インターロックされた操作の基本的なアラインメント要件を既に満たしています。だからあなたは本当にこの問題を考え過ぎているようです。 –

+0

このThreadSafeCounterクラスは、単なる単なる例です。私が実際にやっていることは、std :: shared_ptrのようなものですが、いくつかの追加機能があり、そのためにヒープにカウンタを置く必要があります。 – zeroes00

+0

カウンタはヒープ上にあることができますが、どのようにそれをやっているのかを割り当てる必要はありません。もしstd :: shared_ptrのようなものであれば、クラス内でインライン化され、整列されていれば_align_mallocが実行されます)パフォーマンスを落とし、b)ロックフリーの環境で問題を引き起こす可能性がある独自のロックセクションにあなたを押しつける – Necrolis

答えて

5

ヒープ・アロケータは、返されたアドレスをネイティブ・プラットフォームのワード・サイズに整列しています。 x86では4バイト、x64では8バイト。あなたはの長さがで、MSVCのどちらのプラットフォームでも32ビットを使用しています。 _aligned_malloc()フープをジャンプする必要はありません。

3

これはプラットフォームのアーキテクチャの詳細ですが、アラインメントよりもアトミックな操作が多いことに注意してください。プラットフォームのABIは通常、基本的なデータ型のアライメントが、アトミックを含むあらゆる操作が機能するようにすることを保証します。 malloc()は、たとえあなたが1バイトを要求しても、あなたにミスアライメントされたポインタを返すべきではありません。

http://en.wikipedia.org/wiki/False_sharingを調整する必要があります(つまり、sizeof(long))必要があることを意味するだけでなく、同じキャッシュライン内でアトミックにアクセスされる変数を1つだけホストするようにする必要があります。

これらのカウンターの配列を使用/使用する予定がある場合は、特に重要です。

マイクロソフトのコンパイラは、特定の構造体の配置を保証するようにコンパイラに指示するために__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キャストはかなり厄介です。しかし、これは私には、このオブジェクトがタイプ特性を利用して正しいアラインメントをもっていることを示唆しています。

関連する問題