スレッド内にデータを置く代わりに、データをスレッドの外に移動し、保護してから、両方のスレッドからデータにアクセスします。
以下は、あなたができることのスケッチです。
class Counter
{
public:
Counter():mMutex(),mCounter(0){}
int inc()
{
QMutexLocker ml(&mMutex);
return mCounter++;
}
int dec()
QMutexLocker ml(&mMutex);
return mCounter--;
}
private:
QMutex mMutex;
int mCounter;
Q_DISABLE_COPY(Counter)
};
class ThreadA : public QThread
{
public:
ThreadA(Counter* ctr);
/* ... */
};
class ThreadB : public QThread
{
public:
ThreadB(Counter* ctr);
/* ... */
};
の構成は、ウィキペディア(強調鉱山)から、モニターCounter
と呼ばれることがよくあります。
並行プログラミングでは、モニターは、複数のスレッドによって安全に使用されることを目的としたオブジェクトまたはモジュールです。モニターの特徴は、そのメソッドが相互排除して実行されることです。つまり、各時点で、最大で1つのスレッドがそのメソッドのいずれかを実行している可能性があります。この相互排除は、データ構造を更新する並列コードに関する推論と比較して、モニターの実装に関する推論を大幅に簡素化します。
この特定のケースでは、より効率的な構成はですQAtomicInt
。これは、特別なCPU命令を使用することでアトミック性を獲得します。これは、他のスレッド構造を実装するために使用できる低レベルのクラスです。
編集-完全な例
共有状態のスレッドを正しく使用することは簡単ではありません。キューに入れられた接続または他のメッセージベースのシステムでQtシグナル/スロットを使用することを検討することをお勧めします。
あるいは、Adaなどの他のプログラミング言語は、ネイティブ構造としてスレッドとモニター(保護されたオブジェクト)をサポートします。
これが完全な実例です。QTest::qSleep
これは単なるサンプルコードであり、実際のコードでは使用しないでください。
objs.h
#ifndef OBJS_H
#define OBJS_H
#include <QtCore>
class Counter
{
public:
Counter(int init);
int add(int v);
private:
QMutex mMutex;
int mCounter;
Q_DISABLE_COPY(Counter)
};
class CtrThread : public QThread
{
Q_OBJECT
public:
CtrThread(Counter& c, int v);
void stop();
protected:
virtual void run();
private:
bool keeprunning();
Counter& mCtr;
int mValue;
bool mStop;
QMutex mMutex;
};
#endif
objs.cpp
#include "objs.h"
Counter::Counter(int i):
mMutex(),
mCounter(i)
{}
int Counter::add(int v)
{
QMutexLocker ml(&mMutex);
return mCounter += v;
}
///////////////////////////////////////
CtrThread::CtrThread(Counter& c, int v):
mCtr(c),
mValue(v),
mStop(false),
mMutex()
{}
void CtrThread::stop()
{
QMutexLocker ml(&mMutex);
mStop = true;
}
void CtrThread::run()
{
while(keeprunning())
{
mCtr.add(mValue);
}
}
bool CtrThread::keeprunning()
{
QMutexLocker ml(&mMutex);
return ! mStop;
}
test.cpp
#include <QtCore>
#include <QTest>
#include "objs.h"
int main(int argc, char** argv)
{
QCoreApplication app(argc, argv);
qDebug() << "Initalising";
Counter ctr(0);
CtrThread thread_a(ctr, +1);
CtrThread thread_b(ctr, -1);
qDebug() << "Starting Threads";
thread_a.start();
thread_b.start();
for (int i = 0; i != 15; ++i)
{
qDebug() << "Counter value" << ctr.add(0);
QTest::qSleep(1000);
}
qDebug() << "Stopping Threads";
thread_a.stop();
thread_b.stop();
thread_a.wait();
thread_b.wait();
qDebug() << "Finished";
return 0;
}
test.pro
QT=core testlib
HEADERS=objs.h
SOURCES=test.cpp objs.cpp
コンパイルして実行すると、値が出力され、サンプル出力が表示されます。
Initalising
Starting Threads
Counter value 0
Counter value 11057
Counter value 28697
Counter value 50170
Counter value 60678
Counter value 73773
Counter value 84898
Counter value 96441
Counter value 118795
Counter value 135293
Counter value 146107
Counter value 158688
Counter value 169886
Counter value 201203
Counter value 212983
Stopping Threads
Finished