Share via


並列コンテナーと並列オブジェクト

並列パターン ライブラリ (PPL: Parallel Patterns Library) には、要素へのスレッド セーフなアクセスを提供するいくつかのコンテナーとオブジェクトが含まれています。

同時実行コンテナーは、最も重要な操作への安全な同時実行セーフ アクセスを提供します。これらのコンテナーの機能は、標準テンプレート ライブラリ (STL: Standard Template Library) が提供するコンテナーに似ています。例えば、 concurrency::concurrent_vector クラスのような std::vector 、以外は、クラス、 concurrent_vectorクラス、並列内の要素を追加することができます。同じコンテナーへの読み取りアクセスと書き込みアクセスの両方を必要とする並列コードがある場合、同時実行コンテナーを使用します。

同時実行オブジェクトは、コンポーネント間で同時に共有されます。同時実行オブジェクトの状態を並行して計算するプロセスでは、同じ状態を連続して計算するプロセスと同じ結果が生成されます。Concurrency::combinable 同時オブジェクト型の 1 つの例のクラスです。combinable クラスを使用すると、計算を並行して実行した後、その計算を最終結果に結合できます。同期機構 (ミューテックスなど) を使用して共有変数またはリソースへのアクセスを同期する場合、同時実行オブジェクトを使用します。

セクション

ここでは、次の並列コンテナーと並列オブジェクトについて詳しく説明します。

同時実行コンテナー:

  • concurrent_vector クラス

    • concurrent_vector と vector の違い

    • 同時実行セーフな操作

    • 例外セーフ

  • concurrent_queue クラス

    • concurrent_queue と queue の違い

    • 同時実行セーフな操作

    • 反復子のサポート

  • concurrent_unordered_map クラス

    • 相違点の間の concurrent_unordered_map と unordered_map

    • 同時実行セーフな操作

  • concurrent_unordered_multimap クラス

  • concurrent_unordered_set クラス

  • concurrent_unordered_multiset クラス

同時実行オブジェクト:

  • combinable クラス

    • メソッドおよび機能

concurrent_vector クラス

Concurrency::concurrent_vector クラスでは、同様に、シーケンス コンテナー クラス、 std::vector クラス、ランダムにその要素にアクセスすることができます。concurrent_vector クラスを使用すると、同時実行セーフの追加操作と要素アクセス操作を実行できます。追加操作では、既存のポインターまたは反復子は無効化されません。反復子のアクセス操作と走査操作も同時実行セーフです。

Dd504906.collapse_all(ja-jp,VS.110).gifconcurrent_vector と vector の違い

concurrent_vector クラスは、vector クラスとよく似ています。concurrent_vector オブジェクトに対する追加、要素アクセス、および反復子アクセスの各操作の複雑さは、vector オブジェクトの場合と同じです。concurrent_vectorvector の違いを次に示します。

  • concurrent_vector オブジェクトに対する追加、要素アクセス、反復子アクセス、および反復子走査の各操作は、同時実行セーフです。

  • 要素を追加できるのは、concurrent_vector オブジェクトの末尾だけです。concurrent_vector クラスには insert メソッドは用意されていません。

  • concurrent_vector オブジェクトでは、ユーザーが追加操作を行っても、移動セマンティクスは使用されません。

  • concurrent_vector クラスには erase メソッドまたは pop_back メソッドは用意されていません。vector と同様に、clear メソッドを使用して、concurrent_vector オブジェクトからすべての要素を削除します。

  • concurrent_vector クラスは、要素をメモリ内に連続して格納しません。したがって、配列を使用できるすべての方法で concurrent_vector クラスを使用することはできません。たとえば、concurrent_vector 型の v という名前の変数の場合、式 &v[0]+2 により未定義の動作が発生します。

  • concurrent_vector クラスは、grow_by メソッドおよび grow_to_at_least メソッドを定義します。これらのメソッドは resize メソッドに似ていますが、同時実行セーフである点が異なります。

  • concurrent_vector オブジェクトは、ユーザーが追加やサイズ変更を行っても、要素を再配置しません。これにより、既存のポインターや反復子は、同時実行操作中も有効なまま維持されます。

  • ランタイムは、bool 型の concurrent_vector の特殊なバージョンを定義しません。

Dd504906.collapse_all(ja-jp,VS.110).gif同時実行セーフな操作

concurrent_vector オブジェクトに追加するメソッド、concurrent_vector オブジェクトのサイズを増やすメソッド、または concurrent_vector オブジェクト内の要素にアクセスするメソッドはすべて、同時実行セーフです。この規則の例外は、resize メソッドです。

同時実行セーフである一般的な concurrent_vector メソッドと演算子を次の表に示します。

at

End

operator[]

begin

front

push_back

back

grow_by

rbegin

capacity

grow_to_at_least

rend

empty

max_size

size

ランタイムは、STL との互換性などを提供する運用reserve、同時実行制御-セーフではありません。同時実行セーフではない一般的なメソッドと演算子を次の表に示します。

assign

reserve

clear

resize

operator=

shrink_to_fit

既存の要素の値を変更する操作は、同時実行セーフではありません。同じデータ要素に対する同時読み取り/書き込み操作を同期するには、同期オブジェクト (reader_writer_lock オブジェクトなど) を使用します。同期オブジェクトの詳細については、「同期データ構造」を参照してください。

vector を使用する既存のコードを、concurrent_vector を使用するように変換すると、アプリケーションの動作が変化します。たとえば、concurrent_vector オブジェクトに対して 2 つのタスクを同時に実行する次のプログラムについて考えます。1 つ目のタスクでは、concurrent_vector オブジェクトに要素を追加します。2 つ目のタスクでは、同じオブジェクト内のすべての要素の合計を計算します。

// parallel-vector-sum.cpp
// compile with: /EHsc
#include <ppl.h>
#include <concurrent_vector.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
   // Create a concurrent_vector object that contains a few
   // initial elements.
   concurrent_vector<int> v;
   v.push_back(2);
   v.push_back(3);
   v.push_back(4);

   // Perform two tasks in parallel.
   // The first task appends additional elements to the concurrent_vector object.
   // The second task computes the sum of all elements in the same object.

   parallel_invoke(
      [&v] { 
         for(int i = 0; i < 10000; ++i)
         {
            v.push_back(i);
         }
      },
      [&v] {
         combinable<int> sums;
         for(auto i = begin(v); i != end(v); ++i) 
         {
            sums.local() += *i;
         }     
         wcout << L"sum = " << sums.combine(plus<int>()) << endl;
      }
   );
}

end メソッドは同時実行セーフですが、push_back メソッドの同時呼び出しにより、end によって返される値が変更されます。反復子が走査する要素の数は不確定です。したがって、このプログラムを実行するたびに、異なる結果が生成されることがあります。

Dd504906.collapse_all(ja-jp,VS.110).gif例外セーフ

拡張演算または代入演算が例外をスローする場合、concurrent_vector オブジェクトの状態は無効になります。特に指定がない限り、無効な状態の concurrent_vector オブジェクトの動作は未定義です。ただし、オブジェクトが無効な状態であっても、デストラクターはオブジェクトが割り当てるメモリを解放します。

ベクター要素のデータ型 (_Ty) は、次の要件を満たしている必要があります。それ以外の場合、concurrent_vector クラスの動作は未定義です。

  • デストラクターからはスローしないでください。

  • 既定のコンストラクターまたはコピー コンストラクターからスローする場合、virtual キーワードを使用してデストラクターを宣言しないでください。デストラクターは、ゼロで初期化されたメモリで正常に動作します。

Top

concurrent_queue クラス

Concurrency::concurrent_queue と同じように、クラス、 std::queue クラス、その前面にアクセスし、要素をバックアップすることができます。concurrent_queue クラスを使用すると、同時実行セーフなキューへの登録操作とキューからの削除操作を実行できます。concurrent_queue クラスでは、同時実行セーフではない反復子もサポートされています。

Dd504906.collapse_all(ja-jp,VS.110).gifconcurrent_queue と queue の違い

concurrent_queue クラスは、queue クラスとよく似ています。concurrent_queuequeue の違いを次に示します。

  • concurrent_queue オブジェクトでのキューへの登録操作とキューからの削除操作は、同時実行セーフです。

  • concurrent_queue クラスでは、同時実行セーフではない反復子がサポートされています。

  • concurrent_queue クラスには front メソッドまたは pop メソッドは用意されていません。concurrent_queue クラスは、try_pop メソッドを定義してこれらのメソッドを置換します。

  • concurrent_queue クラスには back メソッドは用意されていません。したがって、キューの最後を参照することはできません。

  • concurrent_queue クラスには、size メソッドの代わりに unsafe_size メソッドが用意されています。unsafe_size メソッドは同時実行セーフではありません。

Dd504906.collapse_all(ja-jp,VS.110).gif同時実行セーフな操作

concurrent_queue オブジェクトにキューを登録するメソッド、または concurrent_queue オブジェクトからキューを削除するメソッドはすべて、同時実行セーフです。

同時実行セーフである一般的な concurrent_queue メソッドと演算子を次の表に示します。

empty

push

get_allocator

try_pop

empty メソッドは同時実行セーフですが、同時実行操作により、empty メソッドが返される前に、キューが拡張または縮小される可能性があります。

同時実行セーフではない一般的なメソッドと演算子を次の表に示します。

clear

unsafe_end

unsafe_begin

unsafe_size

Dd504906.collapse_all(ja-jp,VS.110).gif反復子のサポート

concurrent_queue には、同時実行セーフではない反復子が用意されています。これらの反復子は、デバッグのためにのみ使用することをお勧めします。

concurrent_queue 反復子は、前方にのみ要素を走査します。次の表に、各反復子がサポートする演算子を示します。

[演算子]

Description

operator++

キュー内の次の項目に進みます。この演算子は、前置インクリメントと後置インクリメントの両方のセマンティクスを提供するためにオーバーロードされます。

operator*

現在の項目への参照を取得します。

operator->

現在の項目へのポインターを取得します。

Top

concurrent_unordered_map クラス

Concurrency::concurrent_unordered_map クラスと同様、連想コンテナー クラス、 std::unordered_map 型要素の可変長シーケンスを制御するクラスを std::pair < const Key、Ty >。順不同のマップのキーと値のペアを追加したり、値をキーにファイルの場所は、辞書と考えてください。このクラスは、複数のスレッドまたは同時に共有のコンテナーへのアクセス、挿入または更新する必要のあるタスクがある場合に便利です。

次の使用例を使用しての基本的な構造を示していますconcurrent_unordered_map。次の使用例 ['、'、' i' の範囲の文字のキーを挿入します。操作の順序が決定されますので、最終的な値を各キーも確認されません。ただし、同時に、挿入を実行しても安全です。

// unordered-map-structure.cpp
// compile with: /EHsc
#include <ppl.h>
#include <concurrent_unordered_map.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain() 
{
    //
    // Insert a number of items into the map in parallel.

    concurrent_unordered_map<char, int> map; 

    parallel_for(0, 1000, [&map](int i) {
        char key = 'a' + (i%9); // Geneate a key in the range [a,i].
        int value = i;          // Set the value to i.
        map.insert(make_pair(key, value));
    });

    // Print the elements in the map.
    for_each(begin(map), end(map), [](const pair<char, int>& pr) {
        wcout << L"[" << pr.first << L", " << pr.second << L"] ";
    });
}
/* Sample output:
    [e, 751] [i, 755] [a, 756] [c, 758] [g, 753] [f, 752] [b, 757] [d, 750] [h, 754]
*/

使用例concurrent_unordered_mapマップを実行し、並列操作を削減するを参照してください方法: マップ操作と縮小操作を並列実行する

Dd504906.collapse_all(ja-jp,VS.110).gif相違点の間の concurrent_unordered_map と unordered_map

concurrent_unordered_map クラスは、unordered_map クラスとよく似ています。concurrent_unordered_mapunordered_map の違いを次に示します。

  • The erase, bucket, bucket_count, and bucket_size methods are named unsafe_erase, unsafe_bucket, unsafe_bucket_count, and unsafe_bucket_size, respectively.**unsafe_**の命名規則を示していますこれらのメソッドが同時実行制御-セーフないこと。同時実行の安全性の詳細についてを参照してください操作の同時実行制御-セーフ。

  • 挿入操作を既存のポインター、または反復子を無効にしませんも、マップ内の既存のアイテムの順序を変更しないでください。挿入し、スキャン操作が同時に発生します。

  • concurrent_unordered_mapサポートしているイテレーションのみを転送します。

  • カーソルを無効にしたりしないによって返される反復子を更新equal_range。挿入範囲の末尾に一致しないアイテムを追加できます。開始の反復子に等しいを指しています。

デッドロック、方法がないを避けるためにconcurrent_unordered_mapメモリ アロケーター、ハッシュ関数、またはその他のユーザー定義のコードを呼び出すときに、ロックを保持します。また、ハッシュ関数では常に同じキーと同じ値に評価を確認する必要があります。最適なハッシュ関数キー均一ハッシュ コード領域全体を配布します。

Dd504906.collapse_all(ja-jp,VS.110).gif同時実行セーフな操作

concurrent_unordered_mapクラス同時実行制御-セーフの挿入と要素へのアクセスの操作ができます。挿入操作既存のポインター、または反復子無効にしないでください。反復子のアクセス操作と走査操作も同時実行セーフです。次の表は、一般的に使用される示していますconcurrent_unordered_mapメソッドおよび演算子は、同時実行制御-セーフです。

at

count

find

key_eq

begin

empty

get_allocator

max_size

cbegin

end

hash_function

operator[]

cend

equal_range

挿入

size

countメソッド呼び出すことができます安全にスレッドを同時に実行してから、同時にコンテナーに新しい値を挿入すると別のスレッドの異なる結果が表示されることができます。

次の表は、一般的に使用されるメソッドと同時実行制御-セーフではない演算子を示します。

clear

max_load_factor

rehash

load_factor

operator=

スワップ

これらのメソッドのほかに、任意の方法で始まる**unsafe_**も同時実行制御-セーフではありません。

Top

concurrent_unordered_multimap クラス

Concurrency::concurrent_unordered_multimap クラスに近い、 concurrent_unordered_mapによって、同じキーにマップするのには、複数の値を除くことをクラスします。異なりますconcurrent_unordered_mapで、次の方法があります。

  • Concurrent_unordered_multimap::insert の代わりに反復子を返しますstd::pair<iterator, bool>

  • concurrent_unordered_multimapクラスを提供していない**operator[]**や、 atメソッド。

次の使用例を使用しての基本的な構造を示していますconcurrent_unordered_multimap。次の使用例 ['、'、' i' の範囲の文字のキーを挿入します。concurrent_unordered_multimap複数の値が、キーを有効にします。

// unordered-multimap-structure.cpp
// compile with: /EHsc
#include <ppl.h>
#include <concurrent_unordered_map.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain() 
{
    //
    // Insert a number of items into the map in parallel.

    concurrent_unordered_multimap<char, int> map; 

    parallel_for(0, 10, [&map](int i) {
        char key = 'a' + (i%9); // Geneate a key in the range [a,i].
        int value = i;          // Set the value to i.
        map.insert(make_pair(key, value));
    });

    // Print the elements in the map.
    for_each(begin(map), end(map), [](const pair<char, int>& pr) {
        wcout << L"[" << pr.first << L", " << pr.second << L"] ";
    });
}
/* Sample output:
    [e, 4] [i, 8] [a, 9] [a, 0] [c, 2] [g, 6] [f, 5] [b, 1] [d, 3] [h, 7]
*/

Top

concurrent_unordered_set クラス

Concurrency::concurrent_unordered_set クラスに近い、 concurrent_unordered_mapクラスのキーと値のペアではなく値を管理します。concurrent_unordered_setクラスを提供していない**operator[]**や、 atメソッド。

次の使用例を使用しての基本的な構造を示していますconcurrent_unordered_set。次の使用例 ['、'、' i' の範囲の文字の値を挿入します。同時に、挿入を実行しても安全です。

// unordered-set-structure.cpp
// compile with: /EHsc
#include <ppl.h>
#include <concurrent_unordered_set.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain() 
{
    //
    // Insert a number of items into the set in parallel.

    concurrent_unordered_set<char> set; 

    parallel_for(0, 10000, [&set](int i) {
        set.insert('a' + (i%9)); // Geneate a value in the range [a,i].
    });

    // Print the elements in the set.
    for_each(begin(set), end(set), [](char c) {
        wcout << L"[" << c << L"] ";
    });
}
/* Sample output:
    [e] [i] [a] [c] [g] [f] [b] [d] [h]
*/

Top

concurrent_unordered_multiset クラス

Concurrency::concurrent_unordered_multiset クラスに近い、 concurrent_unordered_setの値が重複することができることにクラスします。異なりますconcurrent_unordered_setで、次の方法があります。

  • Concurrent_unordered_multiset::insert の代わりに反復子を返しますstd::pair<iterator, bool>

  • concurrent_unordered_multisetクラスを提供していない**operator[]**や、 atメソッド。

次の使用例を使用しての基本的な構造を示していますconcurrent_unordered_multiset。次の使用例 ['、'、' i' の範囲の文字の値を挿入します。concurrent_unordered_multiset値が複数回出現することができます。

// unordered-set-structure.cpp
// compile with: /EHsc
#include <ppl.h>
#include <concurrent_unordered_set.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain() 
{
    //
    // Insert a number of items into the set in parallel.

    concurrent_unordered_multiset<char> set; 

    parallel_for(0, 40, [&set](int i) {
        set.insert('a' + (i%9)); // Geneate a value in the range [a,i].
    });

    // Print the elements in the set.
    for_each(begin(set), end(set), [](char c) {
        wcout << L"[" << c << L"] ";
    });
}
/* Sample output:
    [e] [e] [e] [e] [i] [i] [i] [i] [a] [a] [a] [a] [a] [c] [c] [c] [c] [c] [g] [g]
    [g] [g] [f] [f] [f] [f] [b] [b] [b] [b] [b] [d] [d] [d] [d] [d] [h] [h] [h] [h]
*/

Top

combinable クラス

Concurrency::combinable クラスは、細分化された計算を実行し、これらの計算は、最終的な結果にマージすることができます再利用可能なスレッド ローカル記憶域を提供します。combinable オブジェクトは減少変数と考えることができます。

combinable クラスは、複数のスレッドまたはタスク間で共有しているリソースがある場合に便利です。combinable クラスを使用すると、ロック制御なしで共有リソースにアクセスできるため、共有状態を解消できます。したがって、このクラスは、複数のスレッドから共有データへのアクセスを同期するために同期機構 (ミューテックスなど) を使用する代わりの方法として使用できます。

Dd504906.collapse_all(ja-jp,VS.110).gifメソッドおよび機能

次の表に、combinable クラスの重要なメソッドをいくつか示します。combinable クラスのすべてのメソッドの詳細については、「combinable クラス」を参照してください。

メソッド

Description

local

現在のスレッド コンテキストに関連付けられているローカル変数への参照を取得します。

clear

combinable オブジェクトからすべてのスレッド ローカル変数を削除します。

combine

combine_each

指定された combine 関数を使用して、すべてのスレッド ローカル計算のセットから最終値を生成します。

combinable クラスは、マージされた最終結果でパラメーター化されたテンプレート クラスです。既定のコンストラクターを呼び出す場合、_Ty テンプレート パラメーター型には既定のコンストラクターとコピー コンストラクターが必要です。_Ty テンプレート パラメーター型に既定のコンストラクターがない場合は、パラメーターとして初期化関数を使用するコンストラクターのオーバーロードされたバージョンを呼び出します。

combine メソッドまたは combine_each メソッドを呼び出した後、追加データを combinable オブジェクトに格納できます。combine メソッドと combine_each メソッドを複数回呼び出すこともできます。combinable オブジェクト内のローカル値が変更されない場合、combine メソッドと combine_each メソッドは、呼び出されるたびに同じ結果になります。

Dd504906.collapse_all(ja-jp,VS.110).gif

combinable クラスの使用方法の例については、次のトピックを参照してください。

Top

関連トピック

Reference

concurrent_vector クラス

concurrent_queue クラス

concurrent_unordered_map クラス

concurrent_unordered_multimap クラス

concurrent_unordered_set クラス

concurrent_unordered_multiset クラス

combinable クラス