次の例を使用すると、これをよりよく理解できるようになります。これを2つのスレッドで実行しましょう。
#pragma omp parallel for num_threads(2)
for(int i=0; i< 3; i++) {
for (int j=0; j< 3; j++) {
printf("i = %d, j= %d, threadId = %d \n", i, j, omp_get_thread_num());
}
}
その結果、次のようになります。
i = 0, j= 0, threadId = 0
i = 0, j= 1, threadId = 0
i = 0, j= 2, threadId = 0
i = 1, j= 0, threadId = 0
i = 1, j= 1, threadId = 0
i = 1, j= 2, threadId = 0
i = 2, j= 0, threadId = 1
i = 2, j= 1, threadId = 1
i = 2, j= 2, threadId = 1
つまり、最上位のforループに#pragma omp parallel forを追加すると、そのforループのインデックスがスレッド間で分割されます。ご覧のとおり、iのインデックスが同じ場合、スレッドIDも同じです。
その代わりに、ネストされたforループにある組み合わせを並列化できます。この例では、iとjの次の組み合わせを持つことができます。
i = 0, j= 0
i = 0, j= 1
i = 0, j= 2
i = 1, j= 0
i = 1, j= 1
i = 1, j= 2
i = 2, j= 0
i = 2, j= 1
i = 2, j= 2
コードの組み合わせを賢く並列化するために、次のようにcollapseキーワードを追加できます。
#pragma omp parallel for num_threads(2) collapse(2)
for(int i=0; i< 3; i++) {
for (int j=0; j< 3; j++) {
printf("i = %d, j= %d, threadId = %d \n", i, j, omp_get_thread_num());
}
}
その場合、結果は次のようになります。
i = 0, j= 0, threadId = 0
i = 0, j= 1, threadId = 0
i = 1, j= 2, threadId = 1
i = 2, j= 0, threadId = 1
i = 2, j= 1, threadId = 1
i = 2, j= 2, threadId = 1
i = 0, j= 2, threadId = 0
i = 1, j= 0, threadId = 0
i = 1, j= 1, threadId = 0
次に、以前とは異なり、同じインデックスiに対して、異なるスレッドIDが存在する可能性があることがわかります((i=1およびj=2 threadId = 1)の場合(i=1およびj=0 threadId = 0))。つまり、このシナリオでは、iとjの組み合わせがスレッド間で分割されます。