#include <iostream> #include <windows.h> #include <process.h> using namespace std; /*------------------------------------------------------------------------------- 0以上の数値のみを格納するシンプルなリスト ----------------------------------------------------------------------------------*/ class List { private: int size; int index; int* buffer; public: /*------------------------------------------------------- リストのサイズを指定して初期化 ---------------------------------------------------------*/ List( int size ) { this->size = size; this->buffer = new int[ size ]; this->index = -1; for ( int i = 0; i < this->size; ++i ) this->buffer[ i ] = -1; } /*------------------------------------------------------- バッファを削除する ---------------------------------------------------------*/ ~List() { delete[] buffer; } /*------------------------------------------------------- リストに存在する要素の個数 ---------------------------------------------------------*/ int Count() { return this->index + 1; } /*------------------------------------------------------- データを追加する 戻り値は成功時0・失敗時-1 ---------------------------------------------------------*/ int Add( int data ) { if ( index < size && data >= 0 ) { this->index++; this->buffer[ index ] = data; return 0; } else { return -1; } } /*------------------------------------------------------- 指定した位置にある要素を削除する 戻り値は成功時0・失敗時-1 ---------------------------------------------------------*/ int Remove( int pos ) { if ( pos <= index && pos >= 0 ) { //データを1つ左へ移動して要素を消す for ( int i = pos; i < index; ++i ) { this->buffer[ i ] = this->buffer[ i + 1 ]; } //エラーがわかりやすいように未使用領域の初期化をする for ( int i = this->index; i < this->size; ++i ) this->buffer[ i ] = -1; this->index--; return 0; } else { return -1; } } //指定された位置の要素を返す int& operator[] ( int pos ) { if ( pos <= index && pos >= 0 ) { return this->buffer[ pos ]; } else { cout << "境界エラーが発生しました。" << endl; exit( 1 ); } } }; #define COUNT 10000 List list( COUNT ); /*------------------------------------------------------------------------------- グローバル変数にしたListに要素を追加する関数 ----------------------------------------------------------------------------------*/ DWORD WINAPI Add( PVOID pvParam ) { for ( int i = 0; i < COUNT; ++i ) list.Add( i ); return 0; } /*------------------------------------------------------------------------------- グローバル変数にしたListから奇数を削除する関数 ----------------------------------------------------------------------------------*/ DWORD WINAPI Remove( PVOID pvParam ) { for ( int i = 1; i <= COUNT / 2; ++i ) list.Remove( i ); return 0; } /*------------------------------------------------------------------------------- メインプログラム ----------------------------------------------------------------------------------*/ int main(void) { //スレッドに処理を任せる cout << "これからリストに" << COUNT << "個の要素を追加し、その後で奇数を消します。" << endl; cout << "その結果、リスト内には偶数だけが存在する筈です。" << endl; DWORD dwThreadID; HANDLE hThreads[ 2 ]; hThreads[ 0 ] = ( HANDLE ) _beginthreadex ( ( void * ) NULL, ( unsigned ) 0, ( unsigned (__stdcall *) (void *) ) Add, ( void * ) 0, ( unsigned ) 0, ( unsigned * ) &dwThreadID ); hThreads[ 1 ] = ( HANDLE ) _beginthreadex ( ( void * ) NULL, ( unsigned ) 0, ( unsigned (__stdcall *) (void *) ) Remove, ( void * ) 0, ( unsigned ) 0, ( unsigned * ) &dwThreadID ); //全てのスレッドが終了するまで待つ DWORD dw = WaitForMultipleObjects( 2, hThreads, TRUE, INFINITE ); //全てのスレッドを閉じる for ( int i = 0; i < 2; ++i ) CloseHandle( hThreads[ i ] ); cout << "処理が終わりましたので結果を表示します。" << endl; //リスト内の要素を点検 int count = 0; int errors = 0; for ( int i = 0; i < list.Count(); ++i ) { int tmp = list[ i ]; if ( ( tmp % 2 ) != 0 ) { count++; } if ( list[ i ] <= -1 ) { errors++; } } cout << "奇数が" << count << "個ありました。" << endl; cout << "破損している要素(値が-1以下のデータ)が" << errors << "個ありました。" << endl; cout << endl << endl; return 0; }
このサンプルは、Add
関数でListに数値を追加し、Remove
関数でList内から奇数を削除する処理をマルチスレッドで行っています。注目して欲しいところは、「Listの要素が破損する」点です。サンプルのListは非常に単純な作りで、スレッドセーフなものではないので、格納しているデータが整合性のないものになってしまいます。これが並列処理ではスレッドセーフなコンテナを使わなければならない理由です。
インテルTBBのコンテナはスレッドセーフなので、基本的にはデータの整合性は保たれるようになっています。そのため、TBBでプログラミングをする際には必ずインテルTBBのコンテナを使用するべきです。なお、このサンプルはコンテナ以外にも問題がありますが、それは今回の内容と関係がないため解説を省きます。
これで、インテルTBBのコンテナを使用する理由が分かったと思うので、次項からインテルTBBのコンテナを個々に解説します。