確認した環境
- Windows10
- Visual Studio Community 2015 Update 3
- CPU Intel(R) Core(TM) i7-4790
- コア数4、論理プロセッサ数8
使用するスレッド数を指定する2つの方法
forループ内の処理を並列で処理したい場合、
OpenMP が有効になっていれば#pragma omp parallel for
をfor文の直前に加えることで並列処理になります。
#pragma omp parallel for for (int i = 0; i < N; ++i) { hoge(); }
このときの並列処理を実行するスレッド数は、omp_get_max_threads
関数で得られる値です。
使用するスレッド数を指定したい場合、方法は2つあります。
一つはomp_set_num_threads
関数を使う方法です。
以下のソースコードのように書きます。
int num = 4; omp_set_num_threads(num); #pragma omp parallel for for (int i = 0; i < N; ++i) { hoge(); }
もう一つは#pragma
にnum_threads
を追加する方法です。
int num = 4; #pragma omp parallel for num_threads(num) for (int i = 0; i < N; ++i) { hoge(); }
ちなみにいずれの方法においても、指定するスレッド数はコンパイル時に決まっている必要はありません。 実行時に値を指定しても、その指定した値で並列化されます。
2つの方法の違い
omp_get_max_threads
関数の戻り値が異なる
omp_set_num_threads
関数を使用する方法では、omp_get_max_threads
関数の戻り値が
omp_set_num_threads
で指定した値になります。
一方num_threads
を追加する方法では、指定したスレッド数がomp_get_max_threads
関数の戻り値に影響しません。
以下のソースコードで試します。
#include <iostream> #include <omp.h> int main(int argc, char* argv[]) { std::cout << "omp_get_max_threads = " << omp_get_max_threads() << std::endl; #ifdef SWITCH omp_set_num_threads(4); #pragma omp parallel for #else #pragma omp parallel for num_threads(4) #endif for (int i = 0; i < 10; ++i) { #pragma omp critical { std::cout << "i = " << i << ", omp_get_thread_num" << omp_get_thread_num() << ", omp_get_num_threads = " << omp_get_num_threads() << ", omp_get_max_threads = " << omp_get_max_threads() << std::endl; } } std::cout << "omp_get_max_threads = " << omp_get_max_threads() << std::endl; return 0; }
omp_set_num_threads
関数を使用する方法(上記ソースコードのSWITCHが define されているとき)での
結果は以下のようになりました。
omp_set_num_threads
関数の前後でomp_get_max_threads
関数の戻り値が変化していることが分かります。
今回の場合8から4に変化しています。
omp_get_max_threads = 8 i = 0, omp_get_thread_num0, omp_get_num_threads = 4, omp_get_max_threads = 4 i = 1, omp_get_thread_num0, omp_get_num_threads = 4, omp_get_max_threads = 4 i = 2, omp_get_thread_num0, omp_get_num_threads = 4, omp_get_max_threads = 4 i = 8, omp_get_thread_num3, omp_get_num_threads = 4, omp_get_max_threads = 4 i = 9, omp_get_thread_num3, omp_get_num_threads = 4, omp_get_max_threads = 4 i = 6, omp_get_thread_num2, omp_get_num_threads = 4, omp_get_max_threads = 4 i = 7, omp_get_thread_num2, omp_get_num_threads = 4, omp_get_max_threads = 4 i = 3, omp_get_thread_num1, omp_get_num_threads = 4, omp_get_max_threads = 4 i = 4, omp_get_thread_num1, omp_get_num_threads = 4, omp_get_max_threads = 4 i = 5, omp_get_thread_num1, omp_get_num_threads = 4, omp_get_max_threads = 4 omp_get_max_threads = 4
次に、num_threads
を追加する方法(上記ソースコードのSWITCHが define されていないとき)での
結果は以下のようになりました。
omp_get_max_threads
関数の戻り値が変化していないことが分かります。
omp_get_max_threads = 8 i = 0, omp_get_thread_num0, omp_get_num_threads = 4, omp_get_max_threads = 8 i = 1, omp_get_thread_num0, omp_get_num_threads = 4, omp_get_max_threads = 8 i = 2, omp_get_thread_num0, omp_get_num_threads = 4, omp_get_max_threads = 8 i = 8, omp_get_thread_num3, omp_get_num_threads = 4, omp_get_max_threads = 8 i = 9, omp_get_thread_num3, omp_get_num_threads = 4, omp_get_max_threads = 8 i = 6, omp_get_thread_num2, omp_get_num_threads = 4, omp_get_max_threads = 8 i = 7, omp_get_thread_num2, omp_get_num_threads = 4, omp_get_max_threads = 8 i = 3, omp_get_thread_num1, omp_get_num_threads = 4, omp_get_max_threads = 8 i = 4, omp_get_thread_num1, omp_get_num_threads = 4, omp_get_max_threads = 8 i = 5, omp_get_thread_num1, omp_get_num_threads = 4, omp_get_max_threads = 8 omp_get_max_threads = 8
そして、いずれの方法でも指定した並列数(今回の場合4)で動いていることが分かります。