C++
OpenMPでの同時実行性
サーチ…
前書き
このトピックでは、OpenMPを使用したC ++の並行処理の基本について説明します。 OpenMPはOpenMPタグでより詳細に文書化されています。
並列性または並行性は、コードの実行を同時に意味します。
備考
OpenMPは組み込みのコンパイラ機能であるため、特別なヘッダやライブラリは必要ありません。ただし、 omp_get_thread_num()
などのOpenMP API関数を使用する場合は、 omp.h
とそのライブラリをインクルードする必要があります。
コンパイル時にOpenMPオプションが有効になっていないと、OpenMP pragma
文は無視されます。コンパイラのマニュアルでコンパイラオプションを参照することができます。
- GCCは
-fopenmp
使用し-fopenmp
- Clangは
-fopenmp
- MSVCは
/openmp
使用し/openmp
OpenMP:パラレルセクション
この例は、コードのセクションを並列に実行する基本を示しています。
OpenMPはビルトインのコンパイラ機能であるため、サポートされているコンパイラでもライブラリを一切使用しません。あなたは、したいと思うかもしれomp.h
あなたはOpenMPのAPI機能のいずれかを使用する場合。
サンプルコード
std::cout << "begin ";
// This pragma statement hints the compiler that the
// contents within the { } are to be executed in as
// parallel sections using openMP, the compiler will
// generate this chunk of code for parallel execution
#pragma omp parallel sections
{
// This pragma statement hints the compiler that
// this is a section that can be executed in parallel
// with other section, a single section will be executed
// by a single thread.
// Note that it is "section" as opposed to "sections" above
#pragma omp section
{
std::cout << "hello " << std::endl;
/** Do something **/
}
#pragma omp section
{
std::cout << "world " << std::endl;
/** Do something **/
}
}
// This line will not be executed until all the
// sections defined above terminates
std::cout << "end" << std::endl;
出力
この例では、2つの可能な出力を生成し、オペレーティングシステムとハードウェアに依存しています。この出力は、そのような実装から発生する競合状態の問題も示しています。
出力A | 出力B |
---|---|
こんにちは世界の終わりを始める | 世界初のハロー・エンド |
OpenMP:パラレルセクション
この例は、コードの塊を並列に実行する方法を示しています
std::cout << "begin ";
// Start of parallel sections
#pragma omp parallel sections
{
// Execute these sections in parallel
#pragma omp section
{
... do something ...
std::cout << "hello ";
}
#pragma omp section
{
... do something ...
std::cout << "world ";
}
#pragma omp section
{
... do something ...
std::cout << "forever ";
}
}
// end of parallel sections
std::cout << "end";
出力
- こんにちは世界は永遠に終わります
- 世界を始めるこんにちは永遠の終わり
- こんにちは永遠に世界の終わりを始める
- 永遠に始まるこんにちは世界の終わり
実行順序は保証されていないため、上記の出力のいずれかを確認することができます。
OpenMP:Parallel For Loop
この例では、ループを等分に分割して並列に実行する方法を示します。
// Splits element vector into element.size() / Thread Qty
// and allocate that range for each thread.
#pragma omp parallel for
for (size_t i = 0; i < element.size(); ++i)
element[i] = ...
// Example Allocation (100 element per thread)
// Thread 1 : 0 ~ 99
// Thread 2 : 100 ~ 199
// Thread 2 : 200 ~ 299
// ...
// Continue process
// Only when all threads completed their allocated
// loop job
...
* 割り当てられた範囲のインデックスは自動的には更新されないので 、並列forループで使用されるベクトルのサイズを変更しないように注意してください。
OpenMP:並列ギャザリング/リダクション
この例は、 std::vector
とOpenMPを使用して縮小または収集を実行する概念を示しています。
我々は複数のスレッドが原料の束を生成する私たちを助けたいシナリオを持っているはず、 int
簡単にするために、ここで使用され、他のデータ型に置き換えることができます。
これは、セグメンテーションフォールトやメモリアクセス違反を避けるためにスレーブからの結果をマージする必要があり、ライブラリやカスタム同期コンテナライブラリを使用したくない場合に特に便利です。
// The Master vector
// We want a vector of results gathered from slave threads
std::vector<int> Master;
// Hint the compiler to parallelize this { } of code
// with all available threads (usually the same as logical processor qty)
#pragma omp parallel
{
// In this area, you can write any code you want for each
// slave thread, in this case a vector to hold each of their results
// We don't have to worry about how many threads were spawn or if we need
// to repeat this declaration or not.
std::vector<int> Slave;
// Tell the compiler to use all threads allocated for this parallel region
// to perform this loop in parts. Actual load appx = 1000000 / Thread Qty
// The nowait keyword tells the compiler that the slave threads don't
// have to wait for all other slaves to finish this for loop job
#pragma omp for nowait
for (size_t i = 0; i < 1000000; ++i
{
/* Do something */
....
Slave.push_back(...);
}
// Slaves that finished their part of the job
// will perform this thread by thread one at a time
// critical section ensures that only 0 or 1 thread performs
// the { } at any time
#pragma omp critical
{
// Merge slave into master
// use move iterators instead, avoid copy unless
// you want to use it for something else after this section
Master.insert(Master.end(),
std::make_move_iterator(Slave.begin()),
std::make_move_iterator(Slave.end()));
}
}
// Have fun with Master vector
...