QThread
基本的に、長年の API バグがあります。常に破壊可能な状態にあるとは限りません。C++ では、デストラクタを安全に呼び出すことができる場合、オブジェクトは破壊可能な状態にあると見なされます。ランニングの破壊QThread
はエラーです。AQThread
は単なるスレッド コントローラであり、「スレッド」自体ではありません。がどのように機能するかを考えてみてくださいQFile
。開いているかどうかに関係なく、いつでも破壊できます。ファイルの概念をリソースとして真にカプセル化します。AQThread
は、ネイティブ (システム) スレッドのラッパーとしては薄すぎます。それを破棄すると、ネイティブ スレッドが存在する場合でも、それを終了したり破棄したりしません。これはリソース リーク (スレッドは OS リソースです) であり、人々はこの問題に何度もつまずきます。
アプリケーションのmain()
関数が戻ると、C/C++ ランタイム ライブラリの実装によってアプリケーションのすべてのスレッドが終了し、事実上アプリケーション全体が終了します。これがあなたが望む行動であるかどうかはあなた次第です。あなたは、イベントループを実行しているスレッドであるはずquit()
ですwait()
。イベント ループのないスレッドの場合、quit()
はノーオペレーションであり、独自の終了フラグを実装する必要があります。スレッドを破棄する前に、スレッドをオンにする必要 があります。wait()
これは、競合状態を防ぐためです。
以下は の安全なラッパーですQThread
。再実装できないため、これは final クラスですrun
。これは重要です。なぜなら、run の再実装は何もしないような方法で実行され、クラスのコントラクトをquit
破る可能性があるからです。
#include <QThread>
#include <QPointer>
class Thread : public QThread {
using QThread::run; // final
public:
Thread(QObject * parent = 0) : QThread(parent) {}
~Thread() { quit(); wait(); }
};
class ThreadQuitter {
public:
typedef QList<QPointer<Thread>> List;
private:
List m_threads;
Q_DISABLE_COPY(ThreadQuitter)
public:
ThreadQuitter() {}
ThreadQuitter(const List & threads) : m_threads(threads) {}
ThreadQuitter(List && threads) : m_threads(std::move(threads)) {}
ThreadQuitter & operator<<(Thread* thread) {
m_threads << thread; return *this;
}
ThreadQuitter & operator<<(Thread& thread) {
m_threads << &thread; return *this;
}
~ThreadQuitter() {
foreach(Thread* thread, m_threads) thread->quit();
}
};
次のように使用できます。
#include <QCoreApplication>
int main(int argc, char ** argv) {
QCoreApplication app(argc, argv);
QObject worker1, worker2;
Thread thread1, thread2;
// Style 1
ThreadQuitter quitter;
quitter << thread1 << thread2;
// Style 2
ThreadQuitter quitterB(ThreadQuitter::List() << &thread1 << &thread2);
//
worker1.moveToThread(&thread1);
worker2.moveToThread(&thread2);
thread1.start();
thread2.start();
QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
return app.exec();
}
から戻るmain
と、スレッドはquit()
すべてのワーカー スレッドを終了します。これにより、スレッドを並行して巻き上げることができます。次に、thread2.~Thread
そのスレッドが終了するのを待ってからthread1.~Thread
、同じことを行います。スレッドはなくなり、オブジェクトはスレッドレスになり、安全に破棄できます。worker2.~QObject
最初に が呼び出され、続いてworker1.~QObject
.