SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

インテルTBBを通じて学ぶ並列処理

スレッドセーフとインテルTBBのコンテナ

インテルTBBを通じて学ぶ並列処理(3)


  • X ポスト
  • このエントリーをはてなブックマークに追加

SimpleList2:問題があるマルチスレッドのプログラム
#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のコンテナを個々に解説します。

次のページ
スレッドセーフな動的配列:concurrent_vector

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
インテルTBBを通じて学ぶ並列処理連載記事一覧

もっと読む

この記事の著者

インドリ(インドリ)

分析・設計・実装なんでもありのフリーエンジニア。ブログ「無差別に技術をついばむ鳥(http://indori.blog32.fc2.com/)」の作者です。アドバイザーをしたり、システム開発したり、情報処理技術を研究したりと色々しています。座右の銘は温故知新で、新旧関係なく必要だと考えたものは全て学...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/4861 2010/04/27 12:09

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング