Shoeisha Technology Media

CodeZine(コードジン)

記事種別から探す

POCO::Foundationでデザインパターン - マルチスレッド編 -

オープンソースC++用クラスライブラリPOCO活用講座(5)

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2008/07/04 14:00

今回は、しばらく続いたPOCO::Foundationライブラリの締めくくりとして、スレッド関連のクラスを説明します。応用例としては、Worker Thread(ワーカースレッド)パターンというデザインパターンを用いたサンプルコードをとりあげます。

目次

はじめに

 本連載ではPOCO(C++ Portable Components)というオープンソースのC++用クラスライブラリを紹介してきました。今回は、POCO::Foundationライブラリの締めくくりとしてスレッド関連のクラスを説明します。応用例としては、Worker Thread(ワーカースレッド)パターンを用いたサンプルコードをとりあげます。ワーカースレッド・パターンは、参考資料で紹介されているデザインパターンです。

これまでの記事

  1. POCO::Netライブラリによる組み込みWebサーバの実装
  2. 5分で使えるLoggingフレームワーク - POCO::Foundation -
  3. テキスト処理もPOCOにおまかせ
  4. POCO流ファイル処理あれこれ

対象読者

 オブジェクト指向を理解し、ネイティブC++のクラスライブラリを活用できる方を対象としています。

必要な環境

プラットフォーム

 POCOは、多様なプラットフォームで動作させることが可能です。現時点でWindows、Mac OS X、Linux、HP-UX、Tru64、Solaris、QNXでの動作を保証しています。

コンパイラ

 いわゆる標準C++のコードに対応したものが必要です。POCO内部でSTLを使用しています。サンプルコードは、Windows Vista環境で「Microsoft Visual C++ 2008 Express Edition」を用いてビルドし、動作の検証を行いました。

スレッドクラスの基本

 スレッドとは、簡単に言うと、プロセスをさらに細分化した最小の実行単位です。1つのプロセス内で並列処理を行う際には、複数のスレッドを扱うこと(マルチスレッド化)を避けて通ることはできません。また、最近普及しているマルチコアのCPUでは物理的にスレッドを同時実行することが可能ですから、マルチスレッドをうまく活用すれば処理能力の大幅な向上が見込めます。

 ただし注意すべき点があります。並列動作は直感的にイメージするのが難しいため、発見困難なバグを埋めこんでしまうことがあるのです。うっかり不具合を混入させないためにも、POCOのクラスなどを利用して、見通しのよいプログラムを書くことが大切だと言えます。

POCOのスレッドクラス

 スレッドの扱い方はプラットフォームによって当然異なります。しかし、POCOではスレッドに関するプラットフォームの差異をクラスで吸収しているので、環境に依存しないコーディングが可能です。

 以下の表では、POCO::Foundationライブラリ内から、スレッド関連(Threading)としてパッケージされているクラスのうち、主要なものをピックアップしました。

Threadingパッケージの主要なクラス
クラス名概要
ConditionPOSIX仕様のCondition Variablesをシミュレートしたクラス
Runnableスレッド本体用抽象クラス
ErrorHandlerスレッド関連クラスで使う例外クラスのベースクラス
Eventイベント同期クラス
FastMutexMutexクラス(再帰で使えないが、その分高速)
MutexMutexクラス(再帰でも使える)
RWLock読み書きロック用クラス
ScopedLockスコープ限定のロッククラス
Semaphoreセマフォ処理クラス
SynchronizedObject同期オブジェクト(イベント、Mutex)の親クラス
Threadスレッド管理クラス
ThreadPoolスレッドプールを実装したクラス
Timerスレッドベースのタイマー処理クラス
TimerCallbackタイマー処理で使うコールバック用テンプレートクラス

スレッド処理の基本形

 最も基本的なサンプルは次のようになります。

スレッド処理の基本形ソース
#include "stdafx.h"

#include "Poco/Thread.h"
#include "Poco/Runnable.h"

#include <iostream>

//Runnableクラスを継承したスレッド本体クラス
class Worker: public Poco::Runnable
{
    // スレッドのメイン処理
    void run()
    {
        std::cout << "excute!" << std::endl;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    // workerスレッドの実体
    Worker          worker;

    // スレッド管理クラス
    Poco::Thread    thread;

    // workerスレッド開始
    thread.start( worker );

    // スレッドの終了待ち
    thread.join();

    return 0;
}

 スレッド本体の処理は、Poco::Runnableクラスを継承したクラスに記述します。スレッドの生成や実行はPoco::Threadクラスを用いて行います。Poco::Runnableクラスは、ごくシンプルな抽象クラス(インターフェースクラス)で、ひとつの純粋仮想関数run()しか定義されていません。

Runnableクラス定義
class Runnable
{
public:
    Runnable();
    virtual ~Runnable();

    virtual void run() = 0;
};

 Poco::Runnableを継承するサブクラスでは、メンバ関数run()をオーバーライドします。ここで記述する処理内容がスレッドのメインルーチンとなります。上記のサンプルでは、“excute!”という文字列を1回だけコンソールに出力して終えるようにしました。

 スレッドの生成と開始は、Poco::Threadクラスのstart()で行います。

start()定義
void start( Poco::Runnable &target );

 start()メソッドにPoco::Runnableのサブクラスを引数として渡すと、スレッドが生成されます。スレッド内からは、サブクラスのrun関数がコールバックの形で実行されます。メインスレッド側では、スレッドを起動した後は、それが終了するまでjoin()関数を使って待機するようにします。join関数は、引数で与えられたサブクラスのrun関数が終わるまでブロッキングされ、制御を戻しません。

 なお、スレッドの終了はスレッド自身が行うように記述する必要があります。起動した側からスレッドを終了させるのではなく、その終了を待つようにします。これが一般的なスレッド処理の基本フローとなります。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • WINGSプロジェクト 高江 賢(タカエ ケン)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2017年5月時点での登録メンバは52名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂き...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XMLD...

バックナンバー

連載:オープンソースC++用クラスライブラリPOCO活用講座
All contents copyright © 2005-2017 Shoeisha Co., Ltd. All rights reserved. ver.1.5