C++11 とインテル® TBB スレッドの併用

インテル® oneTBB

この記事は、インテル® デベロッパー・ゾーンに掲載されている「Mixing C++11 and TBB Threads」 (http://goparallel.sourceforge.net/mixing-c11-tbb-threads/) の日本語参考訳です。


インテル® TBB には、標準の名前空間で利用できるスレッドクラスが含まれています。これらのスレッドクラスと C++11 のクラスを併用することはできるのでしょうか? それは状況により異なります。ここでは、どのような場合に併用できるのか説明します。

C++11 コンパイラーでインテル® TBB を使用する場合、C++11 の新機能とインテル® TBB を併用できます。詳しくは、http://goparallel.sourceforge.net/make-code-readable-c-lambda-functions-tbb/ をご覧ください。C++11 の標準ライブラリーに詳しい方は、スレッドが完全にサポートされていることをご存知でしょう。そこで気になるのが、インテル® TBB と C++11 の標準ライブラリーを併用できるかどうかということです。

最初に、C++11 のスレッドについて触れておきましょう (「C++11 Concurrency」シリーズ (英語) が参考になります)。

標準の名前空間には、std::thread と呼ばれる C++11 の名前空間があります。(これは、コンパイラー・ベンダーにより実装されなければならない外部ライブラリーですが、C++11 標準の一部であり、C++11 言語の一部でもあります。) スレッド名前空間のクラスは、簡単に使用できます。例えば、前述の「C++11 Concurrency」シリーズにある最初のいくつかのサンプルをコンパイルすると、記事で説明されているように、スレッドのインスタンスを生成してスレッド関数に渡すだけで実行できます。

注: G++ でスレッドコードをコンパイルし実行すると、問題が発生する可能性があります。これは既知の問題です (詳しくは、こちらこちらをご覧ください)。スレッドを有効にしてコンパイルしたときに、マルチスレッドを有効にする必要があることを示すメッセージが表示される場合は、次のコマンドライン・オプションを試してみてください。

g++ -std=c++11 -pthread -Wl,–no-as-needed threads.cpp

threads.cpp は、実際に使用するソースコード・ファイルに置き換えてください。-Wl,–no-as-needed を追加することで、筆者のプログラムでは問題が解決しました。本題に戻りましょう。

thread ヘッダーファイルにあるスレッドクラスのほかにも、mutex ヘッダーファイルにある mutex クラスなどがあります。これも簡単に使用できます。

問題は、インテル® TBB でこれらすべてのコードを記述し、スレッド制御に C++11 を使用したい場合、どうすれば良いのでしょうか?

選択肢は 3 つあります。1 つ目は、すべての C++11 ランタイム・ライブラリー機能を使用しないようにします。

2 つ目は、C++11 と併用できるようにインテル® TBB コードを記述し、インテル® TBB スレッドを使用せず、C++ スレッドのみを使用します。筆者が試したところ、以下のヘッダーファイルを追加することで、インテル® TBB と C++11 を併用してコードを問題なくコンパイルし、実行することができました。

#include <iostream>

#include <tbb/tbb.h>

#include <tbb/parallel_for.h>

#include <thread>

このコード例から、インテル® TBB (真ん中の 2 つのヘッダーファイル) と C++11 (最後のヘッダーファイル) を併用していることが分かります。これだけで、問題なくコンパイルし実行することができました。

3 つ目は、tbb 名前空間ではなく、std 名前空間で利用可能なインテル® TBB のスレッドクラスを使用します。このスレッドクラスを利用するには、ヘッダーファイルを変更する必要があります。

#include <thread>

上記のヘッダークラスを次のように変更します。

#include<!--DVFMTSC--> <tbb/compat/thread>

これで、スレッドクラスを std::thread として C++11 と併用できるようになります。そして、ヘッダーファイルを C++11 互換にするため、g++ のコンパイラー・オプションに次の定義を追加します。

g++ -std=c++11 -pthread -Wl,–no-as-needed -D TBB_IMPLEMENT_CPP0X=1 threads.cpp -ltbb

「C++11 Concurrency」の最初のサンプルは、インテル® TBB の thread ヘッダーファイルに変更し、コンパイラー・オプションを変更するだけでコンパイルし実行できます。しかし、2 つ目のサンプルはエラーになります。出力されたテンプレート・エラー・メッセージを検証した結果、インテル® TBB のスレッドクラスのインスタンスをベクトルで使用するとコンパイラーが正しく処理できないことが分かりました (C++11 のスレッドクラスのインスタンスではこの問題は発生しません)。

まとめ

3 つ目の選択肢の問題を解決するにはどうすれば良いのでしょうか? 時間をかけて、インテル® TBB のスレッド・オブジェクトを標準ライブラリーのベクトルで使用できるようにすることもできますが、代わりに、次のいずれかのオプションを推奨します。C++11 と最新の標準ベクトルを使用している場合は、C++11 のスレッドクラスに切り替えます。あるいは、C++11 のクラスを使用せずに、インテル® TBB のクラスだけを使用します。つまり、(筆者が検証したいくつかのコードのように) 2 つのライブラリーを併用しても問題がない場合は併用しますが、そうでない場合は、併用させるため無駄に時間を費やす代わりに、どちらか一方を使用するようにします。

インテル® TBB のスレッドクラスの実装は、C++11 標準に似ていますが、全く同じではありません。そのため、これらのライブラリーを併用する場合は、まず試してみて、上手く動作するかどうか確認したほうが良いでしょう。

タイトルとURLをコピーしました