japan.internet.comThe Internet & IT Network
Twitter
RSS
  • ニュース
  • コラム
  • リサーチ
  • ヘッドライン
  • 特集
  • ブログ
  • プレスリリース
  • 専門チャンネル
  • イベント
  • ランキング
  • ニュースメール
2009年11月22日
文字サイズ文字サイズ小文字サイズ中文字サイズ大
事業仕分けによる次世代スーパーコンピューターの開発予算削減について、どうお考えですか?
賛成
反対
どちらとも言えない
投票締切 11/30 12:00
デベロッパー2005年10月4日 22:00

Windows のスレッドプーリング

海外海外internet.com発の記事
  • Post to Twitter
  • Post to Facebook
  • このエントリーを含むはてなブックマーク
  • この記事をクリップ!
  • Buzzurlにブックマーク
  • Yahoo!ブックマークに登録
  • newsing it!
  • この記事をokyuuへインポート

はじめに

 スレッドプーリングとは、複数の実行スレッドを管理し、処理を各スレッドに分散させるためのテクニックである。場合によっては、同時実行制御などの機能も、スレッドプーリングの一部と考えられる。スレッドプーリングは、以下の処理を作業を行うのに適した方法である。

複雑な処理を管理する

 スレッドプーリングはステートベースの処理に適している。システムをいくつかのステートマシンに分解できる場合には、スレッドプーリングを利用してそのシステムを効果的に実現することができる。これには、たいていの場合にマルチスレッドアプリケーションのデバッグが単純化されるという副次的なメリットもある。

アプリケーションの拡張性を高める

 正しく実装すれば、スレッドプールによって同時実行の制限を設け、アプリケーションの拡張性を高めることができる。

リスクを最小限に抑えながら新規コードを追加する

 スレッドプーリングを利用すると、"サンドボックス"と呼ばれる、システムの実行をいくつかの小さな単位に分割するセキュリティモデルを実現できる。"サンドボックス"モデルでは、スレッドプーリングによってプロセス間の結び付きが緩やかになり、プロセスからデータが独立するため安全である。この方式では、プロセスどうしが複雑にからみ合うのではなく、点で接することになる。これにより、保守の手間が大幅に減少する。特に、大規模なマルチスレッドアプリケーションでは効果が大きい。

設計

 スレッドプールの概念モデルは単純で、

  1. スレッドプールがスレッドを開始する
  2. 処理がスレッドプールのキューに入れられる
  3. キュー内の処理が使用可能スレッドで実行される

 という形である。テンプレートを使用すると、プールをスレッド/処理の実装から独立させることができる(このテクニックは静的ポリモーフィズムと呼ばれる)。

図1 スレッドプールのコラボレーション図
図1 スレッドプールのコラボレーション図

 スレッドプールはスレッドの作成を担当する。スレッドはworker::thread_procによって実行を開始する。リクエストはスレッドプールのキューに入れられる。このとき、ワーカーがリクエストの準備をし、リクエストをキューに入れる。スレッドが処理を実行できる状態になったときは、スレッドがthread_pool::get_queued_statusを使用して、スレッドプールに待機中の処理をリクエストする。待機中の処理がない場合は、処理が送信されてくるまで、スレッドは休止状態になる。

チェイニング

 このワーカー実装によって処理をキュー化できるが、さらに一歩進んでみよう。このスレッドプールは問題を個別のステップに分解するのに役に立ち、それによってシステムの能力を最大限に活用しつつ、複雑さとリスクを最小限に抑えることができる。しかし、現在の実装では一度に1つの処理しかキュー化できないので、一連の処理を論理的にまとめるのが難しい。さらに、後続の処理をキュー化するためには、処理がいつ実行されたかを知る手段が必要になる。

具体的な例

 システムをダウンさせ、システムデータを再構築し、システムを再びオンラインにする、という一連の処理がある。これは3つのステップ、3つの処理である。これを次のような形で実装したいと思う。

thread_pool::instance().queue_request(
   (core::chain(), new system_down, new rebuild_data,
    new system_up));

 ここで出てきたチェイン(chain)とは、一種の処理単位のことである。正確には、このチェインは、実際の処理単位(実は処理単位のコンテナ)のコンテナとしてのみ機能する。

struct chain {
struct data : work_unit, std::list<smart_pointer<work_unit> > {
void process();
};

chain() : m_work(new data) {}
chain& operator,(work_unit* p_work);
operator work_unit*() { return m_work; }
smart_pointer<data> m_work;
};    // struct chain

 chain::operatorは、次の処理だけを行う。

m_work->push_back(p_work);
return *this;

 chain::data::process()は、次の処理だけを行う。

front()->process();
pop_front();

// if not empty, requeue
if (true == empty()) return;
thread_pool<worker_thread>::instance().queue_request(this);

コードの使用方法

 まず、使用するスレッドプールを初期化する。スレッドプールはパラメータ付きのシングルトンなので、使用するワーカーの種類ごとに1つのスレッドプールインスタンスが存在する。global::thread_poolクラスは、core::thread_pool<core::worker_thread>を表す便利なtypedefである。

global::thread_pool::instance().initialize();

 core::worker_threadをワーカー実装として使用する場合は、すべての処理がcore::work_unitから派生することになり、このプロセスが呼び出されたときに処理が実行される。

struct mywork : core::work_unit
{
   void process() throw()
   {
      // work is processed here
   }
}

 処理をキュー化するには、クラスのインスタンスを作成し、必要に応じて初期化する。この処理を、thread_pool::queue_requestを使用してキュー化する。

// demonstrate chaining
global::thread_pool::instance().queue_request(
   (core::chain(), new work_1, new work_2, new work_3));

 スレッドプールをシャットダウンするには、thread_pool::shutdownを使用する。

global::thread_pool::instance().shutdown();

 他のスレッドプールを作成するには、ワーカースレッドとその構成部品を定義すればよい。ワーカースレッドでは、request_typeprepare_requestthread_proc必ず定義する必要がある。thread_procに渡されるLPVOIDパラメータは必ず0で、使用してはならない。このパラメータを通じてコンテキストを提供するようスレッドプールを拡張することができる。次のコードでは、io::threadio::thread_poolを定義している。

   // sample io worker thread
   namespace io {
   struct thread
   {
      typedef io::session request_type;
      static void prepare_request(request_type*) throw();
      static void thread_proc(LPVOID) throw();
   };    // struct thread

   struct thread_pool : core::thread_pool<io::thread> {};
   }     // namespace io

 ユーザーはio::thread_pool::instance();を使用してio::thread_poolにアクセスできる。

デモプログラムについて

 デモプログラムは次のことを行う。

  • global::thread_poolインスタンスの初期化
  • 3種類の処理のインスタンス化
  • 処理をまとめるチェインのインスタンス化
  • 処理のキュー化と実行
  • スレッドプールのシャットダウン

 チームで開発を行っている場合は、大きな処理を小さな処理単位に簡単に分割し、チーム内で分配することができる。それぞれの処理単位は独立してテストでき、かつ、最終的な製品として統合もできる。それぞれの開発者は、担当範囲内で自分の仕事をまっとうすればよいのだ。

 スレッドプールは、拡張性とパフォーマンスに優れた大規模システムを短期間で安全に開発するための素晴らしいツールである。

 ぜひ試していただきたい。

著者紹介

Joshua Emele(Joshua Emele)
サンフランシスコ在住。Plugware Solutions, Ltd. に勤務。C++ でのネットワーク、データベース、ワークフロー アプリケーション開発を専門とする。人生とパートナーをこよなく愛し、クラシック ギター、ハイキング、デジタル機器を好む。

Plugware Solutions, Ltd. ― 設計、レビュー、統合、実装に関するコンサルティング サービスを業務とする。Plugware Web Services Platform の開発元。
  • プリンター用
  • 記事を転送
  • Post to Twitter
  • Post to Facebook
  • このエントリーを含むはてなブックマーク
  • この記事をクリップ!
  • BuzzurlにブックマークBuzzurlにブックマーク
  • Yahoo!ブックマークに登録
  • newsing it!
  • この記事をokyuuへインポート
最新トップニュース
Graphic Design Forum
【Graphic Design Forum】
流動的媒体と静的媒体に関する見解(11月18日)
「IT の耳」
「IT の耳」
【書評】『Hyper-V スタートアップバイブル』――仮想化についてのすぐれた解説書(11月20日)
百式のネットビジネス研究
百式のネットビジネス研究
世界でもっともパワフルな iPod のスピーカー「Wall of Sound」(11月20日)
週刊-サイト別アクセス状況データ
週刊-サイト別アクセス状況データ
ビデオリサーチインタラクティブ調査(月間インターネットオーディエンスデータ)(11月19日)
海外ソーシャルウェブに学ぶ成功の秘訣
海外ソーシャルウェブに学ぶ成功の秘訣
ゲーム業界を襲う世界的な激震。ソーシャルゲーム急成長のインパクト(11月19日)
今さら聞けない初歩からのアクセス解析
今さら聞けない初歩からのアクセス解析
サイトリニューアル前のアクセス解析活用法(11月19日)
成約率、反応率を上げる Web 文章術
成約率、反応率を上げる Web 文章術
文章力を磨き、キャッシュを生み出す Web サイト に(11月19日)
「Webからの脅威」―その傾向と最新対策
「Webからの脅威」―その傾向と最新対策
新たな対策技術:スパムフィルタリングと E-mail レピュテーション(11月18日)
ROI向上のための戦略的WebPR
ROI向上のための戦略的WebPR
「戦略的 WebPR」のしかけ方〜WebPR の効果測定手法とは〜(11月18日)
スマートにソーシャルウェブを構築しよう
スマートにソーシャルウェブを構築しよう
社員力を生かすソーシャルメディアポリシー(11月17日)
DevX
DevX
Erlangを使った並列処理プログラムの作成(11月17日)
Copyright 2009 Japan Internet.com K.K. All Rights Reserved.http://www.internet.com/