Taro3

View on GitHub

SDK を使って基礎を固める

最初のステップは、アプリケーションとワーカーの間で共有されるクラスを実装することです。そのためには、カスタムSDKに頼ることになります。このテクニックについての記憶を新たにする必要がある場合は、第8章「Animations-It’s Alive, Alive!

備忘録として、SDKを説明する図を示します。

image

それぞれの部品の仕事内容を説明してみましょう。

これらのファイルはすべて、IPC メカニズムの各サイド(アプリケーションとワーカー)からアクセス可能でなければなりません。SDKにはヘッダファイルのみが含まれていることに注意してください。これは、SDK の使用法を単純化するために行ったものです。

まずはsdkディレクトリにあるMessageの実装から始めてみましょう。以下の内容のMessage.hファイルを作成します。

#include <QByteArray>

struct Message {
    enum class Type {
        WORKER_REGISTER,
        WORKER_UNREGISTER,
        ALL_JOBS_ABORT,
        JOB_REQUEST,
        JOB_RESULT,
    };

    Message(const Type type = Type::WORKER_REGISTER,
        const QByteArray& data = QByteArray()) :
        type(type),
        data(data)
    {
    }

    ~Message() {}

    Type type;
    QByteArray data;
};

最初に注意すべきなのは、すべての可能なメッセージタイプを詳細に記述した enum class Type です。

C++11 で追加された enum クラス型について簡単に説明します。これは enum のより安全なバージョンです(最初からあるべき姿が enum であると言う人もいるかもしれません)。

私たちは可能な限りenumクラスを使用する傾向がありますが、これはQtのenumの使用法と衝突しない場合を意味します。

ご覧のように、メッセージには2人のメンバーしかいません。

シリアライズ/デシリアライズの責任をMessage呼び出し元に負わせるために、dataを非常に汎用的なものにすることにしました。メッセージのtypeに基づいて、彼らはメッセージの内容を読み書きする方法を知っていなければなりません。

このアプローチを使うことで、MessageRegisterやMessageUnregisterなどのもつれたクラス階層を避けることができます。新しい Message type を追加するのは、単に Type enum class に値を追加し、適切なシリアライズ/デシリアライズを data で行うだけです (これはいずれにせよ行わなければなりません)。

Qt Creatorで見るには、ch10-mandelbrot-ipc.proのMessage.hを忘れずに追加してください。

OTHER_FILES += \
sdk/Message.h

次のヘッダはJobRequest.hです。

#include <QSize>
#include <QPointF>

struct JobRequest
{
    int pixelPositionY;
    QPointF moveOffset;
    double scaleFactor;
    QSize areaSize;
    int iterationMax;
};

Q_DECLARE_METATYPE(JobRequest)

// In ch10-mandelbrot-ipc
OTHER_FILES += \
    sdk/Message.h \
    sdk/JobRequest.h

この struct 要素には、ワーカーが対象のマンデルブロ画像の線を計算するために必要なすべてのデータが含まれています。アプリケーションとワーカーは異なるメモリ空間(あるいは異なる物理マシン)に存在するため、マンデルブロ集合を計算するためのパラメータは何らかの方法で送信されなければなりません。これがJobRequestの目的です。各フィールドの意味は、第9章「マルチスレッドで正気を保つ」のJobResultと同じです。

Q_DECLARE_METATYPE(JobRequest) マクロの存在に注意してください。このマクロは、QtメタオブジェクトシステムにJobRequestを知らせるために使用されます。これはQVariantと組み合わせてクラスを使えるようにするために必要です。QVariantを直接使用するのではなく、QVariantに依存するQDataStreamを使用します。

JobResultといえば、こちらが新しいJobResult.hです。

#include <QSize>
#include <QVector>
#include <QPointF>

struct JobResult
{
    JobResult(int valueCount = 1) :
        areaSize(0, 0),
        pixelPositionY(0),
        moveOffset(0, 0),
        scaleFactor(0.0),
        values(valueCount)
    {
    }

    QSize areaSize;
    int pixelPositionY;
    QPointF moveOffset;
    double scaleFactor;

    QVector<int> values;
};

Q_DECLARE_METATYPE(JobResult)

// In ch10-mandelbrot-ipc
OTHER_FILES += \
    sdk/Message.h \
    sdk/JobRequest.h \
    sdk/JobResult.h

新しいバージョンは、第9章「マルチスレッドで正気を保つ」のプロジェクト例の恥知らずなコピーペーストです (小さな Q_DECLARE_METATYPE を追加しています)。


戻る