プログラミング

 【C++】OpenMPで並列処理をやってみる【macOS Mojave 10.14】

OpenMP

OpenMPはC/C++用の並列計算を簡単に実装できるライブラリ.

有名らしいけど,今回初めて使用してみたのでその備忘録として色々まとめます.

ちなみにタイトルの通り,macOS Mojave 10.14.6での実装.

下準備

まずMacOSでOpenMPを利用するには,Clangではなくgcc/g++にコンパイラを切り替える必要があるようだ.

早速インストールを行う.

ここですでにインストール済みであればせっかくなのでアップデートもしておくと良いでしょう.

そうしたら切り替えるわけだが,まずgccの場所を確認する.

そのあと,先ほどインストールされたgccとg++は,おそらく「/usr/local/bin/」にあるハズ.

一応確認する.

そうしたら,先ほどのgccの場所に対して,新しいgccをldコマンドを用いてリロケートする.

もし,gccの場所が「/usr/bin/」であれば,

のようにする.(このとき gcc-9g++-9 はバージョンによって異なる)

Operation not permitted

MacOSのバージョンによってはこいつが出てくる.

実際に僕も遭遇しました.

そういう人は以下のページを参考にしてSIP(System Integrity Protection)を無効にして試してみてください.

 

参考:EI Capitanでsudo付けているOperation not permittedが出た時の対処法

CLionなどのIDEを用いる場合

もしかしたらIDEの参照しているコンパイラがまだ過去のものかもしれない.

CLionであれば以下を参照してください.

 

参考:コンパイラの切り替え - ヘルプ | CLion

CMakeLists.txtに書くこと

もしCMakeを使う人は参考までに.

なお,このあとの実装はCMakeを用いている.

CMakeLists.txtには最低でも以下の記述が追加で必要になります.

以下はCMakeLists.txt全体の一例.(本記事のCMakeLists.txt)

ちなみに普通にターミナルからコンパルするときは,-fopenmpオプションをつける.

OpenMPを使ってみる

下準備が終わったので本題に入ります.(結構下準備に時間がかかったなんて言えない)

まずは超シンプルなコードから.

なにもしないプログラムだが,まあOpenMPの動作確認としては十分.

入り乱れている.笑

おそらく,あるスレッドが標準出力処理をしているときに,改行( endl )する前に他のスレッドの同じ処理が被ってしまっただけだと思う.

クリティカルセクションの指定

クリティカルセクションとは,ある処理を並列処理しているときに,同時に実行しない領域を指す.

OpenMPでもサポートされているようです.

先ほどのコードを以下のように加筆しました.

そうすると,

入り乱れることはなくなりました.

このクリティカルセクションは上手く使わないと,予想外の結果が返ってくる可能性がある.

例えば,

を実行すると,実行の度に違う結果が返ってくる.

そこで,

とするだけで,おかしな結果が返ってくることはなくなる.

reduction

他にも競合を解消する方法は,reduction指示節を記述する方法がある.

記法は reduction({演算子}: {変数名}) で,スレッド間で共有したい変数をあらかじめ宣言しておくというもの.

例えば先ほどのコードは以下のように書いても期待通りの結果が得られる.

こっちの方がスマートなのかもしれない.

イテレーションループは使えない

使っていて気づいたが, for( auto v : vec ) のようなイテレータを使ったループは並列化できない.

これは,OpenMPが何回ループがあるか事前にわからないから,並列しようがない,ということらしい.

まあ確かにそうだ.笑

おわりに

簡単にではありますが,OpenMPについて記事を書きました.

とりあえず使えそうな情報だけ書きました.

ほとんど備忘録のようなものですが,誰かの興味に刺さったり,困っている人の手助けになれば幸いです.

 


スポンサードリンク