C++における並列処理の基本
並列処理は、複数の計算を同時に行うことでプログラムの実行時間を短縮するための一般的な手法です。C++では、標準ライブラリの一部として並列処理をサポートしています。
スレッド
C++の並列処理の基本は「スレッド」です。スレッドはプログラム内の独立した制御の流れで、複数のスレッドが同時に実行されることで並列処理が可能になります。C++では、<thread>
ヘッダを含めることでstd::thread
クラスを利用できます。
#include <thread>
void function() {
// スレッドで実行する処理
}
int main() {
std::thread t(function); // 新しいスレッドを作成
t.join(); // スレッドが終了するのを待つ
}
ミューテックス
複数のスレッドが同時に同じデータにアクセスすると、データの不整合が発生する可能性があります。これを防ぐために、ミューテックス(相互排他)を使用します。ミューテックスは、一度に1つのスレッドだけが特定のコードを実行できるようにするロックの一種です。
#include <mutex>
std::mutex mtx;
void function() {
mtx.lock();
// ミューテックスで保護された処理
mtx.unlock();
}
以上がC++における並列処理の基本的な概念です。次のセクションでは、これらの概念を用いてUbuntuでの並列処理の環境設定について説明します。
Ubuntuでの環境設定
UbuntuでC++の並列処理を行うためには、適切なコンパイラとライブラリが必要です。ここでは、GCCとOpenMPを使用した環境設定方法を説明します。
GCCのインストール
GCCはGNU Compiler Collectionの略で、C++を含む複数のプログラミング言語をコンパイルするためのツールセットです。Ubuntuでは、以下のコマンドでGCCをインストールできます。
sudo apt update
sudo apt install build-essential
OpenMPの利用
OpenMPは、C++の並列処理を簡単に実装するためのAPIです。GCCを使用してC++のコードをコンパイルする際に、-fopenmp
オプションを指定することでOpenMPを利用できます。
g++ -fopenmp code.cpp -o output
以上がUbuntuでC++の並列処理を行うための基本的な環境設定です。次のセクションでは、これらの設定を用いて具体的な並列処理の実装方法について説明します。
OpenMPを用いた並列処理
OpenMP (Open Multi-Processing) は、C++を含む複数のプログラミング言語で並列処理を実装するためのAPIです。OpenMPは、プログラムの特定の部分を複数のスレッドで並行に実行することを可能にします。
OpenMPの基本的な使用方法
OpenMPを使用するには、まず<omp.h>
ヘッダをインクルードします。
#include <omp.h>
次に、並列に実行したいコードブロックの前に#pragma omp parallel
ディレクティブを追加します。このディレクティブは、以下のコードブロックを複数のスレッドで並行に実行するように指示します。
#pragma omp parallel
{
// ここに並列に実行したいコードを書く
}
OpenMPのスケジューリング
OpenMPでは、#pragma omp for
ディレクティブを使用してループを並列化することができます。このディレクティブは、ループの各イテレーションを異なるスレッドで並行に実行します。
#pragma omp parallel
{
#pragma omp for
for(int i = 0; i < N; i++) {
// ここに並列に実行したいコードを書く
}
}
以上がOpenMPを用いた並列処理の基本的な方法です。次のセクションでは、std::thread
を用いた別の並列処理の実装方法について説明します。
std::threadを用いた並列処理
C++11から、標準ライブラリにはstd::thread
というスレッドライブラリが含まれています。これを使用すると、独立したスレッドを作成し、並列処理を実装することができます。
std::threadの基本的な使用方法
std::thread
を使用するには、まず<thread>
ヘッダをインクルードします。
#include <thread>
次に、std::thread
オブジェクトを作成します。コンストラクタには、新しいスレッドで実行したい関数を指定します。
void function() {
// スレッドで実行する処理
}
int main() {
std::thread t(function); // 新しいスレッドを作成
t.join(); // スレッドが終了するのを待つ
}
std::threadの同期
複数のスレッドが同時に実行されると、データの不整合が発生する可能性があります。これを防ぐために、std::mutex
を使用してデータを保護します。
#include <mutex>
std::mutex mtx;
void function() {
mtx.lock();
// ミューテックスで保護された処理
mtx.unlock();
}
以上がstd::thread
を用いた並列処理の基本的な方法です。次のセクションでは、これらの設定を用いて具体的な並列処理のパフォーマンス評価について説明します。
並列処理のパフォーマンス評価
並列処理の目的は、プログラムの実行時間を短縮することです。したがって、並列処理のパフォーマンスを評価するためには、実行時間の測定が必要です。
実行時間の測定
C++では、<chrono>
ライブラリを使用して高精度の時間測定を行うことができます。以下に、プログラムの実行時間を測定する基本的なコードを示します。
#include <chrono>
auto start = std::chrono::high_resolution_clock::now();
// 測定したいコード
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> diff = end-start;
std::cout << "Time to run the code: " << diff.count() << " s\n";
スピードアップと効率
並列処理のパフォーマンスを評価するための2つの重要な指標は、スピードアップと効率です。
スピードアップは、並列プログラムの実行時間と逐次プログラムの実行時間の比率で定義されます。理想的には、スピードアップは使用するスレッドの数と等しくなることが期待されます。
効率は、スピードアップを使用するスレッドの数で割ったもので、並列プログラムのスケーラビリティを評価するために使用されます。効率が1に近いほど、プログラムはよりスケーラブルです。
以上が並列処理のパフォーマンス評価の基本的な方法です。これらの知識を用いて、自身の並列プログラムのパフォーマンスを評価し、最適化することができます。