主線程(GUI線程)
可重入和線程安全
If a function is not marked as thread-safe or reentrant, it should not be used from different threads. If a class is not marked as thread-safe or reentrant then a specific instance of that class should not be accessed from different threads.
// 可重入
// 比如一個類,在每個線程中創建一個實例進行使用
// 線程安全
// 比如一個類,在每個線程中使用同一個實例
// 沒有標明可重入和線程安全
// 比如一個類,就在一個線程中使用,不要多個線程創建多個實例
線程,線程對象,對象
#include <QCoreApplication> #include <QThread> #include <QDebug> // 每個對象都有一個歸屬的線程,依附在固定的線程上運行 class TestThread : public QThread { private: QObject obj; // 在主線程 protected: void run() { qDebug() << "in TestThread run " << QThread::currentThread(); QObject obj_t; // run函數內,就是進入了線程內部 // obj_t 依附於子線程 qDebug() << "not in run " << obj.thread(); qDebug() << "in run " << obj_t.thread(); qDebug() << "in run this " << this->thread(); // this代表線程對象的指針,線程對象在主線程上構建,所以依附於主線程 // exec(); // 如果要開啟子線程事件循環 } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); TestThread tt; // 線程對象,用於管理線程,並不是線程 tt.start(); // 開啟線程 qDebug() << "in main " << tt.thread(); // 線程對象所在的線程是主線程 return a.exec(); // 主線程事件循環 } /* in TestThread run QThread(0x2802d4f8e0) in main QThread(0x1becf00ae20) not in run QThread(0x1becf00ae20) in run QThread(0x2802d4f8e0) in run this QThread(0x1becf00ae20) */
多線程較好的實踐
參考Qt幫助文檔
**stackoverflow**
The way the QThread lifecycle works is like this:
1. You call QThread::start().
2. At this point, isRunning() should start returning true.
3. The thread internals start. They emit the started() signal.
4. The thread internals call run().
5. Unless you override this in a subclass, run() calls exec().
6. exec() enters an event loop and stays there until quit() or exit() is called.
7. exec() and run() return to the internals.
8. At this point, isFinished() should start returning true and isRunning() false.
9. The internals emit the finished() signal.
10. The internals do some final cleanups.
11. The thread terminates for real.
class Worker : public QObject { Q_OBJECT public slots: void doWork(const QString ¶meter) { QString result; /* ... here is the expensive or blocking operation ... */ emit resultReady(result); } signals: // 工作完成后,發射信號 // 並且把處理的結果作為參數傳出 void resultReady(const QString &result); }; class Controller : public QObject { Q_OBJECT QThread workerThread; public: Controller() { Worker *worker = new Worker; worker->moveToThread(&workerThread); // 改變work的依附線程 // workerThread 結束后,worker被Controller所在線程接管 // workerThread發射finished信號是在workerThread所在線程,而不是在run中 // workerThread和worker在同一線程 // 連接是Qt::DirectConnection connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); // Qt::QueuedConnection connect(this, &Controller::operate, worker, &Worker::doWork); // Qt::QueuedConnection connect(worker, &Worker::resultReady, this, &Controller::handleResults); workerThread.start(); } ~Controller() { workerThread.quit(); workerThread.wait(); } public slots: void handleResults(const QString &); signals: void operate(const QString &); };