TBBのconcurrent_hash_map

5485 ワード

Intel TBBは高同時コンテナクラスを提供し、WindowsまたはLinuxスレッドはこれらのコンテナクラスを使用するか、taskベースのプログラミングと結合することができる(TBB).
1つのコンカレントコンテナでは、マルチスレッドがコンテナへのアクセスと条例の変更を同時に許可し、典型的なC++STLコンテナクラスではコンカレント更新は許可されず、コンテナの悪化を引き起こすコンカレント変更を試みます.STLコンテナは反発ロックを使用して包装することができ、安全にアクセスできるようにし、1つのスレッドだけで1つのコンテナを同時に操作することができますが、この方法は並列を排除し、並列のスピードアップを制限します.
Intel TBBが提供する容器はより高いレベルの同時性があり、以下の方法によって:
  • Fine-grained locking:ロックが必要な部分だけをロックし、コンテナ上でマルチスレッド操作を実現し、マルチスレッドが異なる部分にアクセスすると、同期して行うことができます.
  • Lock-free techniques:他の干渉スレッドの影響を修正します.

  • 高同時コンテナは、STLコンテナよりも高い消費電力を有することが典型的であり、高同時コンテナに対する操作はSTLコンテナよりも多く消費されるため、高同時コンテナを用いてSTLコンテナよりも高速化する場合、シリアル性能よりも優れていることに注意されたい.
    concurrent_hash_map
    concurrenthashmapはhashテーブルであり、並列アクセスを許可し、テーブルはKeyからタイプTへのマッピングであり、タイプHashCompareはどのようにhashを定義し、どのように2つのKeyを比較するかを定義する.
    次の例ではconcurrent_を作成します.hash_map,このKeyは文字列であり,対応するデータは行列Dataに文字列が出現する回数である.
    #include "tbb/concurrent_hash_map.h"
    #include "tbb/blocked_range.h"
    #include "tbb/parallel_for.h"
    #include 
    
    using namespace tbb;
    using namespace std;
    
    // Structure that defines hashing and comparison operations for user's
    type.
    struct MyHashCompare {
        static size_t hash( const string& x ) {
            size_t h = 0;
            for( const char* s = x.c_str(); *s; ++s )
                h = (h*17)^*s;
            return h;
        }
        //! True if strings are equal
        static bool equal( const string& x, const string& y ) {
            return x==y;
        }
    };
    // A concurrent hash table that maps strings to ints.
    typedef concurrent_hash_map<string,int,MyHashCompare> StringTable;
    
    // Function object for counting occurrences of strings.
    struct Tally {
        StringTable& table;
        Tally( StringTable& table_ ) : table(table_) {}
        void operator()( const blocked_range<string*> range ) const {
            for( string* p=range.begin(); p!=range.end(); ++p ) {
                StringTable::accessor a;
                table.insert( a, *p );
                a->second += 1;
            }
        }
    };
    const size_t N = 1000000;
    string Data[N];
    void CountOccurrences() {
    // Construct empty table.
    StringTable table;
    
    // Put occurrences into the table
    parallel_for( blocked_range<string*>( Data, Data+N, 1000 ),
                    Tally(table) );
    
    // Display the occurrences
    for( StringTable::iterator i=table.begin(); i!=table.end(); ++i )
        printf("%s %d
    "
    ,i->first.c_str(),i->second); }

    concurrenthashmapはタイプstd::pair要素のコンテナを演じ、コンテナ要素にアクセスすると更新または読み取りに興味があります.テンプレートクラスconcurrent_hash_mapはこの2つの目的をサポートし、クラスaccessorとconst_に対応する.accessorは、スマートポインタを担当し、accessorは更新(write)アクセスを表し、要素を指すと、accessorが完了するまで他のすべてのテーブルを探すkeyがブロックされます.const_アクセスは似ていますが、読み取りアクセスのみを表す以外は、マルチconst_accessorsは同じ要素を同時に指すことができ,頻繁に読むが更新が少ない場合,この特徴は並列状況を極めて改善する.
    メソッドfindとinsertはaccessorまたはconst_を採用するアクセスはパラメータとしてconcurrent_に伝えますhash_mapは更新または読み取り専用アクセスを要求しているかどうか、このメソッドが戻ってくると、アクセスが終了するまで、accessorまたはconst_要素へのアクセスが他のスレッドをブロックするため、accessorまたはconst_をできるだけ削減するため、accessorは破棄されます.accessorライフサイクルは、内部ブロックで宣言し、できるだけブロックが終了する前にこのaccessorを解放します.次の例は、ループを書き換え、releaseを使用してaccessorのライフサイクルを終了します.
    StringTable accessor a;
    for( string* p=range.begin(); p!=range.end(); ++p ) {
        table.insert( a, *p );
        a->second += 1;
        a.release();
    }

    メソッドremove(key)も同時に動作し、書き込みアクセスを暗黙的に要求するため、このKeyを削除する前に、他の既存のkey上のアクセスが終了するのを待つことができる.