C/C++でpthreadを使ったマトリックス(行列)の加算・減算をマルチスレッドで実装する方法
本記事では、マルチスレッド環境を活用して行列(マトリックス)の加算と減算を行う方法を解説します。C/C++では、POSIXスレッド(pthread)を使用することで、複数のスレッドを同時に実行でき、大規模な行列演算の処理時間を短縮できます。
基本的な考え方
ここでは2つの行列AとBを用意し、それぞれのサイズは m × n とします。各スレッドが担当する行を受け持ち、その行に対して加算または減算を計算します。サンプルコードでは、コア数を3(CORE=3)とし、加算用に3スレッド、減算用に3スレッドの合計6スレッドを生成して、行列全体を3分割して並列処理しています。
サンプルコード
#include<iostream>
#include <pthread.h>
#include <cstdlib>
#include <cstdint>
#define CORE 3
#define MAX 3
using namespace std;
int AMat[MAX][MAX] = {{10, 20, 30},
{40, 50, 60},
{70, 80, 50}
};
int BMat[MAX][MAX] = {{80, 60, 20},
{30, 20, 15},
{10, 14, 35}
};
pthread_t thread[CORE * 2];
int add[MAX][MAX], sub[MAX][MAX];
void* addMatrices(void* arg) {
intptr_t core = (intptr_t)arg;
// 各スレッドが行列加算の1/3を担当
for (int i = core * MAX / 3; i < (core + 1) * MAX / 3; i++) {
for (int j = 0; j < MAX; j++) {
add[i][j] = AMat[i][j] + BMat[i][j];
}
}
}
void* subtraction(void* arg) {
intptr_t core = (intptr_t)arg;
// 各スレッドが行列減算の1/3を担当
for (int i = core * MAX / 3; i < (core + 1) * MAX / 3; i++) {
for (int j = 0; j < MAX; j++) {
sub[i][j] = AMat[i][j] - BMat[i][j];
}
}
}
void display(){
cout << "Matrix A: " << endl;
for(int i = 0; i < MAX; i++) {
for(int j = 0; j < MAX; j++) {
cout << AMat[i][j] << " ";
}
cout << endl;
}
cout << "\nMatrix B: " << endl;
for(int i = 0; i < MAX; i++) {
for(int j = 0; j < MAX; j++) {
cout << BMat[i][j] << " ";
}
cout << endl;
}
}
void displayRes(){
cout << "\nAddition: " << endl;
for(int i = 0; i < MAX; i++) {
for(int j = 0; j < MAX; j++) {
cout << add[i][j] << " ";
}
cout << endl;
}
cout << "\nSubtraction: " << endl;
for(int i = 0; i < MAX; i++) {
for(int j = 0; j < MAX; j++) {
cout << sub[i][j] << " ";
}
cout << endl;
}
}
main() {
display();
int step = 0;
for (int i = 0; i < CORE; i++) {
pthread_create(&thread[i], NULL, &addMatrices, (void*)step);
pthread_create(&thread[i + CORE], NULL, &subtraction, (void*)step);
step++;
}
for (int i = 0; i < CORE * 2; i++) {
pthread_join(thread[i], NULL);
}
displayRes();
}
実行結果
Matrix A: 10 20 30 40 50 60 70 80 50 Matrix B: 80 60 20 30 20 15 10 14 35 Addition: 90 80 50 70 70 75 80 94 85 Subtraction: -70 -40 10 10 30 45 60 66 15
コードの解説
1. 行列の分割とスレッドへの割り当て
addMatrices 関数と subtraction 関数は、引数として受け取ったコア番号(core)をもとに、自分が担当する行の範囲を計算します。具体的には core * MAX / 3 から (core + 1) * MAX / 3 - 1 までの行を処理するため、3つのスレッドで行列全体を均等に分担できます。
2. intptr_t を使った安全な引数渡し
pthreadのスレッド関数は void* 型の引数を受け取る必要があります。整数値を直接ポインタにキャストするとコンパイラ警告が出る場合があるため、intptr_t 型を経由することで、ポインタサイズと整数サイズの差異を吸収し、安全に変換しています。
3. スレッドの生成と同期
pthread_create() でスレッドを生成し、pthread_join() ですべてのスレッドの完了を待機します。これにより、全スレッドの計算が終了したことを保証してから結果を表示できるため、データ競合による不整合を防げます。
コンパイル方法
pthreadを使用する場合は、リンク時に pthread ライブラリを指定する必要があります。Linux環境では以下のようにコンパイルします。
g++ sample.cpp -o sample -lpthread
まとめ
このようにpthreadを利用すれば、行列の行ごとに処理を分割して並列実行でき、シングルスレッドよりも効率的に加算・減算を行えます。行列サイズが大きくなるほど並列化の効果は顕著になるため、科学技術計算や画像処理などの分野で有効な手法です。
-
ポインタ(アドレス渡し)を使って加算と減算を同時に求めるC++プログラム
問題の概要 2つの数 a と b があると仮定しましょう。ここで、(a + b) と (a − b) の両方を計算できる関数を定義する必要があります。しかし、C++の関数では return 文で返せる値は最大1つまでという制約があります。 そこで、複数の結果を扱いたい場合には、関数の引数にポインタ型の出力パラメータを用意し、呼び出し側から変数のアドレスを渡す方法が有効です。本記事の問題では、a を a + b の値に、b を a − b の値に更新することを考えます。関数を呼び出す際には、この2つの変数のアドレスを渡す必要があります。 例えば、入力が a = 15、b = 18 だった場合、
-
C++で0・1・2のみの配列をソートする方法|DNF(オランダ国旗)アルゴリズムを解説
0、1、2 のみで構成された配列が与えられたとき、すべての「0」を先頭に、「1」をその次に、「2」を末尾に配置するように要素を並べ替えることを考えます。このとき、追加のメモリを使用せずに配列をインプレース(in-place)でソートする必要があります。この問題は、DNF(Dutch National Flag:オランダ国旗)ソートアルゴリズムを使うことで効率的に解くことができます。入出力の例例1入力:arr[ ] = {2, 0, 0, 1, 2, 1}出力:0 0 1 1 2 2説明: DNFソートアルゴリズムを用いて0・1・2を含む配列を並べ替えると、{0, 0, 1, 1, 2, 2}