久久久久久久av_日韩在线中文_看一级毛片视频_日本精品二区_成人深夜福利视频_武道仙尊动漫在线观看

如何安全地銷(xiāo)毀 QThread?

How to safely destruct a QThread?(如何安全地銷(xiāo)毀 QThread?)
本文介紹了如何安全地銷(xiāo)毀 QThread?的處理方法,對(duì)大家解決問(wèn)題具有一定的參考價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧!

問(wèn)題描述

我想正確地銷(xiāo)毀 Qt 5.3 中的 QThread.

I want to properly destruct a QThread in Qt 5.3.

到目前為止我有:

MyClass::MyClass(QObject *parent) : QObject(parent) {
    mThread = new QThread(this);
    QObject::connect(mThread, SIGNAL(finished()), mThread, SLOT(deleteLater()));
    mWorker = new Worker(); // inherits from QObject
    mWorker->moveToThread(mThread);
    mThread->start();
}

MyClass::~MyClass() {
    mThread->requestInterruption();
}

我的問(wèn)題是在一天結(jié)束時(shí)我仍然得到:

My problem is that at the end of the day I still get:

QThread:線程仍在運(yùn)行時(shí)被銷(xiāo)毀

QThread: Destroyed while thread is still running

推薦答案

安全線程

在 C++ 中,類(lèi)的正確設(shè)計(jì)是可以隨時(shí)安全地銷(xiāo)毀實(shí)例.幾乎所有 Qt 類(lèi)都以這種方式運(yùn)行,但 QThread 不會(huì).

這是您應(yīng)該使用的類(lèi):

// Thread.hpp
#include <QThread>
public Thread : class QThread {
  Q_OBJECT
  using QThread::run; // This is a final class
public:
  Thread(QObject * parent = 0);
  ~Thread();
}

// Thread.cpp
#include "Thread.h"
Thread::Thread(QObject * parent): QThread(parent)
{}

Thread::~Thread() {
  quit();
  #if QT_VERSION >= QT_VERSION_CHECK(5,2,0)
  requestInterruption();
  #endif
  wait();
}

它會(huì)表現(xiàn)得很好.

另一個(gè)問(wèn)題是Worker對(duì)象會(huì)被泄露.不要將所有這些對(duì)象放在堆上,只需讓它們成為 MyClass 或其 PIMPL 的成員.

Another problem is that the Worker object will be leaked. Instead of putting all of those objects on the heap, simply make them members of MyClass or its PIMPL.

成員聲明的順序很重要,因?yàn)槌蓡T將按照聲明的相反順序被銷(xiāo)毀.因此,MyClass 的析構(gòu)函數(shù)將依次調(diào)用:

The order of member declarations is important, since the members will be destructed in the reverse order of declaration. Thus, the destructor of MyClass will, invoke, in order:

  1. m_workerThread.~Thread() 此時(shí)線程結(jié)束并消失,m_worker.thread() == 0.

  1. m_workerThread.~Thread() At this point the thread is finished and gone, and m_worker.thread() == 0.

m_worker.~Worker 由于對(duì)象是無(wú)線程的,所以在任何線程中銷(xiāo)毀它都是安全的.

m_worker.~Worker Since the object is threadless, it's safe to destroy it in any thread.

~QObject

因此,將工作線程及其線程作為 MyClass 的成員:

Thus, with the worker and its thread as members of MyClass:

class MyClass : public QObject {
  Q_OBJECT
  Worker m_worker;          // **NOT** a pointer to Worker!
  Thread m_workerThread;    // **NOT** a pointer to Thread!
public:
  MyClass(QObject *parent = 0) : QObject(parent),
  // The m_worker **can't** have a parent since we move it to another thread.
  // The m_workerThread **must** have a parent. MyClass can be moved to another
  // thread at any time.
    m_workerThread(this)
  {
    m_worker.moveToThread(&m_workerThread);
    m_workerThread.start();
  }
};

而且,如果您不希望實(shí)現(xiàn)在接口中,那么使用 PIMPL 也是如此

And, if you don't want the implementation being in the interface, the same using PIMPL

// MyClass.hpp
#include <QObject>
class MyClassPrivate;
class MyClass : public QObject {
  Q_OBJECT
  Q_DECLARE_PRIVATE(MyClass)
  QScopedPointer<MyClass> const d_ptr;
public:
  MyClass(QObject * parent = 0);
  ~MyClass(); // required!
}

// MyClass.cpp
#include "MyClass.h"
#include "Thread.h"

class MyClassPrivate {
public:
  Worker worker;          // **NOT** a pointer to Worker!
  Thread workerThread;    // **NOT** a pointer to Thread!
  MyClassPrivate(QObject * parent);
};

MyClassPrivate(QObject * parent) :
  // The worker **can't** have a parent since we move it to another thread.
  // The workerThread **must** have a parent. MyClass can be moved to another
  // thread at any time.
    workerThread(parent)
{}

MyClass::MyClass(QObject * parent) : QObject(parent),
  d_ptr(new MyClassPrivate(this))
{
  Q_D(MyClass);
  d->worker.moveToThread(&d->workerThread);
  d->workerThread.start();
}

MyClass::~MyClass()
{}

QObject 成員出身

我們現(xiàn)在看到關(guān)于任何 QObject 成員的出身的硬性規(guī)則出現(xiàn)了.只有兩種情況:

QObject Member Parentage

We now see a hard rule emerge as to the parentage of any QObject members. There are only two cases:

  1. 如果 QObject 成員沒(méi)有從類(lèi)中移動(dòng)到另一個(gè)線程,它必須是類(lèi)的后代.

  1. If a QObject member is not moved to another thread from within the class, it must be a descendant of the class.

否則,我們必須QObject 成員移動(dòng)到另一個(gè)線程.成員聲明的順序必須使得線程在對(duì)象之前銷(xiāo)毀.如果無(wú)效破壞駐留在另一個(gè)線程中的對(duì)象.

Otherwise, we must move the QObject member to another thread. The order of member declarations must be such that the thread is to be destroyed before the object. If is invalid to destruct an object that resides in another thread.

只有在以下斷言成立時(shí)才能安全地銷(xiāo)毀 QObject:

It is only safe to destruct a QObject if the following assertion holds:

Q_ASSERT(!object->thread() || object->thread() == QThread::currentThread())

線程被破壞的對(duì)象變成無(wú)線程的,并且!object->thread()保持不變.

An object whose thread has been destructed becomes threadless, and !object->thread() holds.

有人可能會(huì)爭(zhēng)辯說(shuō)我們不打算"將我們的班級(jí)轉(zhuǎn)移到另一個(gè)線程.如果是這樣,那么顯然我們的對(duì)象不再是 QObject,因?yàn)?QObject 具有 moveToThread 方法并且可以隨時(shí)移動(dòng).如果一個(gè)類(lèi)不遵守 Liskov 的替換原則到它的基類(lèi),這是一個(gè)錯(cuò)誤從基類(lèi)聲明公共繼承.因此,如果我們的類(lèi)公開(kāi)繼承自QObject,它必須允許自己隨時(shí)移動(dòng)到任何其他線程.

One might argue that we don't "intend" our class to be moved to another thread. If so, then obviously our object is not a QObject anymore, since a QObject has the moveToThread method and can be moved at any time. If a class doesn't obey the Liskov's substitution principle to its base class, it is an error to claim public inheritance from the base class. Thus, if our class publicly inherits from QObject, it must allow itself to be moved to any other thread at any time.

QWidget 在這方面有點(diǎn)異常.至少,它應(yīng)該使 moveToThread 成為受保護(hù)的方法.

The QWidget is a bit of an outlier in this respect. At the very minimum, it should have made the moveToThread a protected method.

例如:

class Worker : public QObject {
  Q_OBJECT
  QTimer m_timer;
  QList<QFile*> m_files;
  ...
public:
  Worker(QObject * parent = 0);
  Q_SLOT bool processFile(const QString &);
};

Worker::Worker(QObject * parent) : QObject(parent),
  m_timer(this)  // the timer is our child
  // If m_timer wasn't our child, `worker.moveToThread` after construction
  // would cause the timer to fail.
{}

bool Worker::processFile(const QString & fn) {
  QScopedPointer<QFile> file(new QFile(fn, this));
  // If the file wasn't our child, `moveToThread` after `processFile` would
  // cause the file to "fail".
  if (! file->open(QIODevice::ReadOnly)) return false;      
  m_files << file.take();
}

這篇關(guān)于如何安全地銷(xiāo)毀 QThread?的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!

【網(wǎng)站聲明】本站部分內(nèi)容來(lái)源于互聯(lián)網(wǎng),旨在幫助大家更快的解決問(wèn)題,如果有圖片或者內(nèi)容侵犯了您的權(quán)益,請(qǐng)聯(lián)系我們刪除處理,感謝您的支持!

相關(guān)文檔推薦

How can I read and manipulate CSV file data in C++?(如何在 C++ 中讀取和操作 CSV 文件數(shù)據(jù)?)
In C++ why can#39;t I write a for() loop like this: for( int i = 1, double i2 = 0; (在 C++ 中,為什么我不能像這樣編寫(xiě) for() 循環(huán): for( int i = 1, double i2 = 0;)
How does OpenMP handle nested loops?(OpenMP 如何處理嵌套循環(huán)?)
Reusing thread in loop c++(在循環(huán) C++ 中重用線程)
Precise thread sleep needed. Max 1ms error(需要精確的線程睡眠.最大 1ms 誤差)
Is there ever a need for a quot;do {...} while ( )quot; loop?(是否需要“do {...} while ()?環(huán)形?)
主站蜘蛛池模板: 成年人在线电影 | 亚洲高清视频一区二区 | 亚洲欧美日韩久久 | 午夜小电影 | 国产色网站| 蜜桃五月天| 亚洲精品免费在线观看 | 99久久99 | 99国产精品99久久久久久粉嫩 | 台湾佬伊人| 日本a∨精品中文字幕在线 亚洲91视频 | 久久精品亚洲成在人线av网址 | 99精品欧美一区二区三区 | 免费视频中文字幕 | 精品国产免费一区二区三区演员表 | 精品国产乱码一区二区三 | 欧美中文字幕一区二区三区亚洲 | 成人h动漫精品一区二区器材 | 一区二区三区视频在线观看 | 久久精品亚洲 | 一级片av| 欧美午夜剧场 | 久久精品国产99国产精品 | 欧美一级视频 | 老司机成人在线 | 日韩a在线 | 国产免费看 | 久久精品免费观看 | 国产一区| 狠狠操狠狠搞 | 亚洲一二三区av | 国产午夜视频 | 婷婷开心激情综合五月天 | 手机av在线 | 天天综合网91 | 成年人在线视频 | 亚洲在线看 | 亚洲精品视频一区 | 欧美日韩91 | 激情五月婷婷在线 | 成av在线|