Qt
スレッドと同時実行性
サーチ…
備考
こことここの公式ドキュメントにはすでに述べられているいくつかのノートがあります :
- オブジェクトに親がある場合は、親と同じスレッドになければなりません。つまり、新しいスレッドに移動することはできません。また、親とオブジェクトが別のスレッドに存在する場合、親にオブジェクトを設定することもできません
- オブジェクトが新しいスレッドに移動されると、そのすべての子も新しいスレッドに移動されます
- 新しいスレッドにのみオブジェクトをプッシュできます。あなたはそれらを新しいスレッドに引き出すことはできません。つまり、オブジェクトが現在住んでいるスレッドからのみ
moveToThread
を呼び出すことができます
QThreadの基本的な使い方
QThread
は、プラットフォームスレッドのハンドルです。スレッドの存続期間を監視し、スレッドが作業を終了するように要求することによってスレッドを管理できます。
ほとんどの場合、クラスを継承することはお勧めできません。デフォルトのrun
メソッドは、イベントをクラスに属するオブジェクトにディスパッチできるイベントループを開始します。クロススレッド信号スロット接続は、 QMetaCallEvent
をターゲットオブジェクトにディスパッチすることによって実装されます。
QObject
インスタンスをスレッドに移動すると、スレッドイベントやスロット/メソッド呼び出しなどのイベントを処理します。
スレッドで作業を行うには、まずQObject
から派生した独自のワーカークラスを作成します。次にスレッドに移動します。オブジェクトはQMetaObject::invokeMethod()
を使って自動的に独自のコードを実行できます。
#include <QObject>
class MyWorker : public QObject
{
Q_OBJECT
public:
Q_SLOT void doWork() {
qDebug() << "doWork()" << QThread::currentThread();
// and do some long operation here
}
MyWorker(QObject * parent = nullptr) : QObject{parent} {}
};
class MyController : public QObject
{
Q_OBJECT
Worker worker;
QThread workerThread;
public:
MyController() {
worker.moveToThread(&workerThread);
// provide meaningful debug output
workerThread.setObjectName("workerThread");
workerThread.start();
// the thread starts the event loop and blocks waiting for events
}
~MyController() {
workerThread.quit();
workerThread.wait();
}
void operate() {
// Qt::QueuedConnection ensures that the slot is invoked in its own thread
QMetaObject::invokeMethod(&worker, "doWork", Qt::QueuedConnection);
}
};
ワーカーが一時的で、作業が完了している間だけ存在する必要がある場合は、 QtConcurrent::run
介してスレッドプール内で実行するQtConcurrent::run
またはスレッドセーフメソッドを実行することをおQtConcurrent::run
。
Qt並行実行
QThreadsとmutexやセマフォーのような低レベルのプリミティブを管理することが複雑すぎると、Qt Concurrent名前空間があなたの探しているものです。これには、より高度なスレッド管理を可能にするクラスが含まれています。
Concurrent Runを見てみましょう。 QtConcurrent::run()
は、新しいスレッドで関数を実行できるようにします。いつあなたはそれを使いたいですか?いくつかの長い操作があり、手動でスレッドを作成したくない場合。
今すぐコード:
#include <qtconcurrentrun.h>
void longOperationFunction(string parameter)
{
// we are already in another thread
// long stuff here
}
void mainThreadFunction()
{
QFuture<void> f = run(longOperationFunction, "argToPass");
f.waitForFinished();
}
つまり、単純なことです:別のスレッドで別の関数を実行する必要があるときは、 QtConcurrent::run
呼び出し、関数とそのパラメータを渡すだけです。
QFuture
は、非同期計算の結果を示します。 QtConcurrent::run
場合、関数の実行をキャンセルすることはできません。
他のスレッドからのスロットの呼び出し
Qtイベントループを使用して操作を実行し、非Qtユーザーがそのイベントループとやり取りする必要がある場合、別のスレッドからの通常の呼び出しを処理するためのスロットを作成すると、他のユーザーの作業が簡単になります。
main.cpp:
#include "OperationExecutioner.h"
#include <QCoreApplication>
#include <QThread>
int main(int argc, char** argv)
{
QCoreApplication app(argc, argv);
QThread thrd;
thrd.setObjectName("thrd");
thrd.start();
while(!thrd.isRunning())
QThread::msleep(10);
OperationExecutioner* oe = new OperationExecutioner;
oe->moveToThread(&thrd);
oe->doIt1(123,'A');
oe->deleteLater();
thrd.quit();
while(!thrd.isFinished())
QThread::msleep(10);
return 0;
}
OperationExecutioner.h:
#ifndef OPERATION_EXECUTIONER_H
#define OPERATION_EXECUTIONER_H
#include <QObject>
class OperationExecutioner : public QObject
{
Q_OBJECT
public slots:
void doIt1(int argi, char argc);
};
#endif // OPERATION_EXECUTIONER_H
OperationExecutioner.cpp:
#include "OperationExecutioner.h"
#include <QMetaObject>
#include <QThread>
#include <QDebug>
void OperationExecutioner::doIt1(int argi, char argc)
{
if (QThread::currentThread() != thread()) {
qInfo() << "Called from thread" << QThread::currentThread();
QMetaObject::invokeMethod(this, "doIt1", Qt::QueuedConnection,
Q_ARG(int,argi), Q_ARG(char,argc));
return;
}
qInfo() << "Called from thread" << QThread::currentThread()
<< "with args" << argi << argc;
}
OperationExecutioner.pro:
HEADERS += OperationExecutioner.h
SOURCES += main.cpp OperationExecutioner.cpp
QT -= gui