以上で述べてきたとおり、現在では並列処理がトレンドになりつつあり、プログラムを並列化する手法についても簡単な物から複雑なものまで様々なものが登場している。以下では、現在利用できる並列化の方法について紹介しておこう。
プロセス/スレッドを利用した実装 並列処理の実装としてもっともプリミティブなものが、プロセス/スレッドを利用した実装である。これは、並列化したい処理を異なるプロセス/スレッドとして動作させる、というものだ。たとえばWindows環境では_beginthread()関数や_beginthreadex()関数、CreateThread()関数などを利用することで、特定の関数を別スレッドで実行できる。また、UNIX環境では主にサーバーアプリケーションなどにおいて、fork()関数を用いてプロセスを生成して処理を行わせる例が多いほか、POSIXスレッド(pthreads)という関数群を利用してマルチスレッド処理を行わせることができる(表1)。
| OS環境 | プロセス/スレッド | 利用できる関数 | |
|---|---|---|---|
| Windows | スレッド生成 | Cランタイムライブラリ | _beginthread()、_beginthreadex()、 |
| Windows API | CreateThread() | ||
| MFC | CWinThreadクラス、AfxBeginThread() | ||
| プロセス生成 | CreateProcess() | ||
| UNIX/Linux | スレッド生成(POSIXスレッド) | pthread_create() | |
| プロセス生成 | fork() | ||
プロセス/スレッドを利用すると柔軟に処理を実装できる半面、共有データの管理やプロセス/スレッドごとの同期についても自前で実装する必要があるため、工数が増えるのが問題である。
現代のマルチタスクOSはプロセス/スレッド同士が安全に情報をやりとりできる仕組みを備えているものの、このような処理は一般的に時間的コストが高く、また設計を間違えるとデッドロックなども発生する可能性がある。特に並列化されたプログラムはデバッグが難しく、「特定の状況でのみ問題が発生する」といったいやらしいトラブルが発生しやすい。
OpenMPを利用した並列化 スレッド/プロセスを明示的に利用して並列処理を実装する場合、並列して処理させたい個所を関数として実装する必要がある。しかし、一般のプログラムにおいては、並列化したい個所というのは特定のループやブロックのみである場合が多い。OpenMPは、プログラムのソースコード中に特定のプラグマを挿入することで並列化すべき個所を指定し、コンパイラに並列化を行わせるものである。
たとえば次の例は、OpenMPを使用してforループを並列化する例である。
example_func1();
#pragma omp parallel for
for(i = 0; i 100; i++ ) {
example_func2(i); /* 並列実行する処理 */
}
example_func3();
「#pragma omp parallel for」プラグマは、このプラグマに続くforループを並列化するようコンパイラに指示するものだ。このように記述されたプログラムは、以下の図4のように関数example_func2()のみが並列実行され、それ以外の処理についてはシングルスレッドで実行される。