プログラミングモデル
マルチスレッド向けプログラムを書く方法は、
大きく分けると次の2種類あります。
方法 | プログラムコードの特徴 |
同じコードを使う | 同一のプログラムコードを使いまわします。同じ処理を複数のスレッドに分割する処理に向いている。 |
別のコードを使う | スレッド単位で処理を書きます。処理単位でスレッドに分割する処理に向いています。 |
これらについて順に説明していきます。
複数のスレッドで同じコードを使う
スレッドごとにデータを分割し、各スレッドで同じコードを使います。
例えば1から100までを加算する処理であれば、
まず次のように、ある数から別のある数までを加算する関数を用意します。
int ichigo_sum(int numbegin,int numend)
{
int ret = 0;
for ( int ichigonum = numbegin; ichigonum <= numend; ichigonum++ )
ret += ichigonum;
return ret;
}
各スレッドでこの関数を呼び出せば、スレッド数によらず同じコードが使えます。
2スレッドの場合の疑似コードは次のようになります。
int ichigoval_1, ichigoval_2, ichigoval;
if (is_thread_1()) ichigoval_1 = ichigo_sum(1, 50);
if (is_thread_2()) ichigoval_2 = ichigo_sum(51, 100);
thread_barrier();
if (is_thread_1()) ichigoval = ichigoval_1 + ichigoval_2;
疑似コードにおいて、
is_thread_1()はスレッド1、is_thread_2()はスレッド2の場合にtrueになる関数、
thread_barrier()はバリア関数です。
最初に各スレッドの結果をichigoval_1とichigoval_2に格納していますが、
この時点では別々の変数(メモリ)に結果に保存するため、同期は必要ありません。
次にスレッド1ではichigoval_1とichigoval_2を読み込むため、
この時点で同期が必要になります。
この疑似コードではバリアを使っていますが、クリティカルセクションでも同期は可能です。
クリティカルセクションを使う場合は、
スレッド間で共有されるichigoval_2に対してクリティカルセクションを用意します。
スレッドごとに別のコードを使う
スレッドごとに別々の処理を行わせたい場合は、別のコードを用意します。
例えば、1から100までを加算した結果と、
1から99までの数を10000から引いた結果を比較したい場合、
各処理を別々のスレッドで実行する疑似コードは次のようになります。
int ichigoval_1, ichigoval_2, ichigoval;
if (is_thread_1()) {
ichigoval_1 = 0;
for ( int ichigonum = 1; ichigonum <= 100; ichigonum++ )
ichigoval_1 += ichigonum;
}
if (is_thread_2()) {
ichigoval_2 = 10000;
for ( int ichigonum = 99; ichigonum >= 1; ichigonum-- )
ichigoval_2 -= ichigonum;
}
thread_barrier();
if (is_thread_1()) {
std::cout << "difference = " << ichigoval_1 - ichigoval_2 << std::endl;
std::cout << "ichigoval_1 = " << ichigoval_1 << std::endl;
std::cout << "ichigoval_2 = " << ichigoval_2 << std::endl;
}
この方法を使うとスレッド単位で細かな処理を記述できますが、
コーディング量が多くなり、またスレッド数に応じて別のプログラムコードが必要になります。
複数のスレッドで同じコードが使えるのであれば、同じコードを使ったほうが良いでしょう。
関連ページ
OpenMPの解説 目次
前の項目: プロセスとスレッド