スレッドクラス
インテルTBBには豊富な機能があり、大概の並行処理はそれを使用すれば解決できるでしょう。しかし、あらかじめインテルTBBに用意されている並列アルゴリズムを適用できない状況で、並列処理をする必要があるかもしれません。この場合は、インテルTBBに用意されているthread
クラスの使用を検討する必要があります。
これからインテルTBBのスレッドを使用するサンプルプロジェクトThreadSampleのコードを掲載するので、まずはそのコードを見てください。
#include <iostream> #include "tbb/compat/thread" using namespace std; /*------------------------------------------------------------------------------- スレッドの使用法を示す為だけのクラス ----------------------------------------------------------------------------------*/ class Foo { public: /* スレッドが行う処理を、関数呼び出し演算子にコーディングします。 */ void operator()() const { cout << "Fooオブジェクトの関数呼び出し演算子が呼び出されました。" << endl; }; }; /*------------------------------------------------------------------------------- メインプログラム ----------------------------------------------------------------------------------*/ int main(void) { Foo obj; //オブジェクトを初期化 thread fooThread( obj ); //オブジェクトを指定 fooThread.join(); //待機する cout << endl; }
このサンプルは、インテルTBBのスレッドを使用して処理を実行する簡単なものです。このコードを理解すれば、インテルTBBのスレッドを使用する方法が分かります。これからその手順を解説します。
インテルTBBのスレッドを使用して並列処理をする為に必要な準備は、並列処理を行いたいオブジェクト(以後、並列オブジェクトと呼びます)に「メソッド呼び出し演算子」を定義するだけです。
準備が終わったら、並列オブジェクトを初期化してから、並列オブジェクトを指定してthread
オブジェクトを初期化します。後は、thread
オブジェクトのjoin
メソッドを実行すれば、並列的に処理が実行された処理を待ちます。これでインテルTBBのスレッドを動かすことができるようになったので、次項ではthread
オブジェクトに用意されているメソッドについて解説します。
スレッドのスリープ概要
複数のスレッドを使って並列処理をする時、単純な処理しかしないスレッドが実行され続けることを避けたい状況があります。この時、任意のスレッドをスリープできると便利です。スレッドのスリープとは、スレッドの処理を一時停止することです。何故スリープする必要があるのかは後で解説します。
インテルTBBのスレッドにもこの機能はあります。これから、サンプルプロジェクトSleepSampleのコードを提示するので、まずはコードを読んでください。
#include <iostream> #include "tbb/compat/thread" using namespace std; /*------------------------------------------------------------------------------- sleep_forメソッドの使用法を示す為だけのクラス ----------------------------------------------------------------------------------*/ class SlowFoo { public: /* スレッドが行う処理を、関数呼び出し演算子にコーディングします。 */ void operator()() const { this_thread::sleep_for( tbb::tick_count::interval_t( 2.0 ) ); //2秒以上スリープ cout << "SlowFooオブジェクトが漸く処理をしました。" << endl; }; }; /*------------------------------------------------------------------------------- メインプログラム ----------------------------------------------------------------------------------*/ int main(void) { cout << "処理を開始しました・・・" << endl; SlowFoo obj; thread fooThread( obj ); fooThread.join(); cout << "処理が終了しました。" << endl; cout << endl; }
このサンプルを実行すると、2秒ぐらい経過してからメッセージが表示されます。注目するべき点はこの部分です。
this_thread::sleep_for( tbb::tick_count::interval_t( 2.0 ) ); //2秒以上スリープ
スリープしたいスレッドのメソッド内で、this_thread::sleep_for
を実行すると、指定値以上の秒数スリープされます。指定値秒ではない点に注意してください。WindowsはリアルタイムOSではないので、正確な時間を指定してスレッドを実行することはできません。
スリープが必要な理由は、この機能が存在しないと、ビジーウェイトをするしかなくなるからです。ビジーウェイトというのは、変数がある値になるまでループ上でチェックすることです。ビジーウェイトはCPUを消費しますし、予期せぬ結果を生みますので、あまり使用されません。ビジーウェイトをする代わりに、スリープを使用するとCPUをビジーウェイトよりも消費しなくなり、ビジーウェイトで発生する並列処理特有のバグも避けられます。
これで、スリープに関する解説は終了です。次項では、スレッド切り替えについて解説します。