SHOEISHA iD

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

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

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

インテルTBBのスレッドクラス

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


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

スレッドの切り替え

 複数のスレッドを扱う際に、今すぐ他のスレッドの処理をしたい場合があります。インテルTBBにはこのための機能も用意されています。この機能もサンプルを見た方が分かりやすいと思いますので、サンプルプロジェクトYieldSampleのコードを見てください。

問題があるyieldのサンプル
#include <iostream>
#include "tbb/compat/thread"
using namespace std;

/*-------------------------------------------------------------------------------

    yieldメソッドの使用法を示す為だけのクラス

----------------------------------------------------------------------------------*/
class ModestFoo
{
public:
    /*
        他のスレッドに処理を譲ってから、自己の処理を開始します。
    */
    void operator()() const 
    {
		cout << "他のスレッドに処理を譲ります(ID:" 
			<< this_thread::get_id() << ")" << endl;
		this_thread::yield(); //他のスレッドを実行する
		cout << "ID:" << this_thread::get_id() << "の処理が始まりました" << endl;
    };
};

/*-------------------------------------------------------------------------------

    メインプログラム

----------------------------------------------------------------------------------*/
int main(void) 
{
    //2つのスレッドを開始
    ModestFoo modest;
    thread modestThread( modest );
    ModestFoo modest1;
    thread modestThread1( modest1 );
    modestThread.join();
    modestThread1.join();

    cout << endl;
}

 このサンプルは、他のスレッドを先に処理するオブジェクトを2つ用意しています。この2つのオブジェクトを並列処理すると、互いに処理を譲り合うので、結局は実行した順に実行されることになります。注目するべき所は、this_thread::yield()this_thread::get_id()です。yieldメソッドを使用すると、今処理している処理を中断し、他のスレッドが処理を実行できるようにできます。get_id()メソッドを使用すると、スレッドを識別するためのIDを取得できます。

 yieldメソッドが必要な理由は、満足に実行できないスレッドが出現するのを避けるためです。例えば、重要な処理をしないスレッドと、重要な処理をするスレッドがあるとします。もし、yieldメソッドを使用できないならば、重要でないスレッドばかりが実行され、重要なスレッドがあまり実行されないかもしれません。この状況では、yieldメソッドが役に立ちます。また、並列処理特有のバグを再現したり、テストを行ったりする場合にも使用すれば便利です。ただし、yieldメソッドはあまり頻繁に使用するべきものではなく、正常に並列処理が行えるように設計するべきなので注意してください。もし、yieldメソッドと、sleep_forメソッドを多用しているシステムがあれば、設計が正しくされているのかチェックするべきです。なぜなら、正しく設計されたシステムは、無理やりスレッドの切り替えを行わなくても、正常に動作するように設計されているものだからです。一般的に、yieldメソッドとsleep_forメソッドが多用されているシステムは、飢餓状態になっている可能性が高いといえます。

 get_id()メソッドが必要な理由は、スレッドを識別する必要があるからです。例えば、このサンプルでget_id()メソッドを使用しないと、何が何だか分からなくなります。また、デバッグ時やスレッドを管理する時に、スレッドを識別できるということは大きな武器となります。今回紹介した3つのメソッド内で一番使える状況が多いでしょう。

 最後に並列処理において重要なことを解説します。このサンプルを実行すると、メッセージが乱れる場合があります。

 この現象はcoutをやみくもに使用すると起こるものです。そのため、前回並列処理でcoutを多用するべきでないと言及しました。また、実務において、並列的に標準出力するのは問題がある仕様です。なぜなら、並列的にさまざまなスレッドから出力されたメッセージを顧客は必要としているのか疑問だからです。特にインテルTBBでは、スレッドを直接扱う機会は少なくなり、予期せぬ数のメッセージが出力されます。仮に将来32コア以上のCPUで動くシステムが、coutにメッセージを出力する場合、混乱を生むのは目に見えています。

 このサンプルは他にも次のように出力される場合があります。

 このように、予期せぬ結果を避けるため、並列処理では極力coutを避けるべきです。使用する場合は、仕様レベルから妥当性を検討する必要があります。

まとめ

 今回はインテルTBBに用意されているスレッドクラスを紹介しました。そして、並列処理では極力coutを避けるべき理由も解説しました。インテルTBBは優れた技術ですが、だからと言って全ての状況に対応できません。インテルTBBに用意されている高度な並列アルゴリズムを使用できない場合、今回紹介したスレッドクラスなどを駆使することになります。

 しかしながら、並列処理の初心者が、実務レベルで使いこなすのは大変難しいでしょう。この連載は基礎の解説を目的としているので、詳しいことは今回述べませんでしたが、スレッドクラスを使用して自分で独自の並列アルゴリズムや、スレッドセーフなクラスを実装するのは多くの知識が必要となります。

 この連載を最後まで読んで、インテルTBBと並列処理の基礎を習得してから、改めて独自並列アルゴリズムやスレッドセーフなクラスの実装にチャレンジしてください。機会があれば、より高度な並列処理の知識を解説したいと考えています。

 次回もTBBの最新情報を盛り込みつつ、並列処理についての解説を盛り込んでいきます。お楽しみに。

参考資料

書籍

Webサイト

修正履歴

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

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

もっと読む

この記事の著者

インドリ(インドリ)

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

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

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

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/5259 2010/07/13 10:03

おすすめ

アクセスランキング

アクセスランキング

イベント

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

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

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

メールバックナンバー

アクセスランキング

アクセスランキング