私はQtの初心者で、Qtでマルチスレッドを探しています。
Qt Documents で学習したように、2つのスレッドに2つのクラスを定義しました。
_#include <QThread>
#include <QMutex>
class thread_a : public QThread
{
Q_OBJECT
public:
explicit thread_a(QObject *parent = 0);
int counter;
protected:
void run();
};
_
そしてCPPファイルで:
_#include "thread_a.h"
thread_a::thread_a(QObject *parent) :
QThread(parent)
{
counter=0;
}
void thread_a::run()
{
counter++;
}
_
2番目のスレッドクラスは同じですが、run()
メソッドに_counter--
_が含まれています。
次に、この2つのスレッドを_main.ccp
_から実行します。
今私の質問:counter
を使用して_thread_a
_および_thread_b
_でQMutex
を共有するにはどうすればよいですか?
スレッド内にデータを置く代わりに、データをスレッドの外に移動して保護し、両方のスレッドからアクセスします。
以下は、あなたができることのスケッチです:
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
の構成要素は、Wikipediaから Monitor と呼ばれることがよくあります(鉱山を強調):
並行プログラミングでは、モニターは、複数のスレッドで安全に使用されることを目的としたオブジェクトまたはモジュールです。モニターの特徴は、そのメソッドが相互に排他的に実行されることです。つまり、各時点で、最大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
OK、実際のプロジェクトの優れたソリューションを提供してくれた@skyhisiに特に感謝します。
私は@skyhisiの投稿と、QMutexと共有変数に関する他の記事を読みました。教育目的で、変数を共有するためのQMutexの使用法のシンプルで明確なサンプルを実装しました(この場合はcounter
)。
_class thread_a : public QThread
{
Q_OBJECT
public:
thread_a(QMutex*, int*);
void shutdown();
private:
QMutex* mutex;
int* counter;
bool isShutdownRequested;
protected:
void run();
};
_
および_thread_a.cpp
_ファイル内:
_thread_a::thread_a(QMutex * m, int* i)
{
counter=i;
isShutdownRequested=false;
mutex=m;
}
void thread_a::run()
{
isShutdownRequested=false;
forever{
//lock mutex for changing in shared variable
mutex->lock();
*counter=*counter+1;
mutex->unlock();
if(isShutdownRequested)
break;
}
}
void thread_a::shutdown()
{
isShutdownRequested=true;
}
_
myMainWindow::RunThreads(bool bl)
スロット:
_int cnt=0;
QMutex mu;
thread* a=new thread_a(&mu, &cnt);
thread* b=new thread_b(&mu, &cnt);
a.start();
b.start();
_
myMainWindow::~myMainWindow()
deconstructorで:
_a->shutdown();
b->shutdown();
_
もう一度ありがとう@skyhisi
QMutexの「ヘルプ」を参照する簡単な例を作成します。この例では、2つのスレッドが(モニターとして)同じ数を変更します。また、S.M.Mousaviのコードも参照しています。ここにコードがあります:
//main.cpp
#include <QCoreApplication>
#include "method.h"
int aNum=0;
QMutex aMutex;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
int *p_no= &aNum;
QMutex *p_Mu = &aMutex;
method mThread1(p_Mu, p_no);
method mThread2(p_Mu, p_no);
mThread1.name = "one";
mThread2.name = "two";
mThread1.start();
mThread2.start();
return a.exec();
}
// method.h
#ifndef METHOD_H
#define METHOD_H
#include <QDebug>
#include <QThread>
#include <QtCore>
#include <QString>
#include <QMutex>
class method: public QThread
{
public:
method(QMutex *mu, int *nu);
void run();
void method1();
void method2();
QString name;
private:
int *number;
QMutex *myMutex;
};
#endif // METHOD_H
//method.cpp #include "method.h"
method::method(QMutex *mu, int *nu)
{
myMutex = mu;
number = nu;
}
void method:: run()
{
for (int i = 0; i<100; i++)
{
if(this->name == "one" )
{
this->method1();
}
else
{
this->method2();
}
}
}
void method::method1()
{
myMutex->lock();
*number += 1;
qDebug()<<*number<<"---"<<this->name;
myMutex->unlock();
}
void method ::method2()
{
myMutex->lock();
*number -= 1;
qDebug()<<*number<<"---"<<this->name;
myMutex->unlock();
}