プログラミング

【C++】標準ライブラリで並列処理をやってみる【std::thread】

c++11-thread

並列処理

前回は,OpenMPというライブラリを使って並列処理を行いました.

しかし,実際に大きなプロジェクトで扱おうとした時に,あまり効果が現れず,むしろ並列化させる場所によっては遅くなってしまう事態に見舞われました.

そこで初心に帰って(?),C++11の標準ライブラリ「Thread」を使って並列処理をやってみよう,という考えに至りました.

備忘録的な部分がありますが,どうかお付き合いください.

std::thread

先ほども言いましたが,C++11から標準ライブラリのひとつとなりました.

ですので,これで書いたコードは,OpenMPみたく下準備的なものが多分いらないはずです.

気をつけるべきこととしては,コンパイル時に,「-std=c++11」(14でも17でも良い)をつけることでしょうか.

私はCMakeListsで管理しているので,さほど大きな問題ではありません.

さっそく試しにコードを書いていきましょう.

サンプルコード

CMakeLists.txt

今回は仮にプロジェクト名は「parallel_sample」としています.

その1:意味なし最低限コード

まずは必要最低限のコードから.

「何かしらの処理」を今回は,何もしないラムダ式で書いていますが,もちろん関数でもいいわけです.

その2:共有変数ある場合

スレッド間で,共有の変数を扱う場合は「std::mutex」を使います.

書き方は主に2種類あって,どちらもミューテックスをロックして,用が済んだらアンロックする作業をしているだけです.

lock()とunlock()を明示的に書く場合は,

lock_guardクラスを用いる場合は,

のように書きます.

lock_guardは,コンストラクタでlockして,デストラクタでunlockするので,そのブロックスコープ全体(lock_guardが破棄されるまで)が排他制御となる.

試していないので分からないが,前者の方が早そうな気はする.

多分あんまり変わらない?

その3:クラスで扱う場合

クラスでも書き方は特に変わらない.

ミューテックスはメンバ変数として保持しておいて良い.

こんな感じ.

並列処理と関係ないけど,メンバ関数内でラムダ式を書く時に,thisを忘れがち.

その4:他クラスのメンバ関数を並列処理

もしかしたら,他クラスのメンバ関数をスレッドに投げたいかもしれない.

そんなときは,以下のように書ける.

コメントに書いてある説明が適切かは分からないが,とりあえず書き方はこう.笑

もちろんラムダ式で書いてもOKだと思う.

追記:メンバ変数としてmutexを定義した場合コピーはできない

記事公開して30分で追記を書いてます.笑

なにかというと,クラスのメンバ変数としてmutexを定義すると,そのクラスはmutexクラスの定義上コピーができなくなります.

例えば,

とかはできない,ってことです.

なぜかというと, mutexはコピーも移動も許されていないようです.

すなわち,それをメンバ変数として持っているクラスも,コピーは不可になります.

これで,さきほどエラーに悩まされました.

なので,以下のようなインスタンス生成も不可能です.

 

おわりに

今回も,最近僕がハマっている?並列処理についてまとめました.

まだ勉強中故に全て理解できておらず,もしかしたらもっとスマートな書き方があるのかもしれない.

個人的には,OpenMPよりこういう風に明示的に書く方が好きです.

ブラックボックスすぎるのは,便利な反面あまり勉強にならないから好きじゃないんですよね...


スポンサードリンク