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

如何安全地銷毀 QThread?

How to safely destruct a QThread?(如何安全地銷毀 QThread?)
本文介紹了如何安全地銷毀 QThread?的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!

問題描述

我想正確地銷毀 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();
}

我的問題是在一天結束時我仍然得到:

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

QThread:線程仍在運行時被銷毀

QThread: Destroyed while thread is still running

推薦答案

安全線程

在 C++ 中,類的正確設計是可以隨時安全地銷毀實例.幾乎所有 Qt 類都以這種方式運行,但 QThread 不會.

這是您應該使用的類:

// 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();
}

它會表現得很好.

另一個問題是Worker對象會被泄露.不要將所有這些對象放在堆上,只需讓它們成為 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.

成員聲明的順序很重要,因為成員將按照聲明的相反順序被銷毀.因此,MyClass 的析構函數將依次調用:

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() 此時線程結束并消失,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 由于對象是無線程的,所以在任何線程中銷毀它都是安全的.

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();
  }
};

而且,如果您不希望實現在接口中,那么使用 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 成員出身

我們現在看到關于任何 QObject 成員的出身的硬性規則出現了.只有兩種情況:

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 成員沒有從類中移動到另一個線程,它必須是類的后代.

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

否則,我們必須QObject 成員移動到另一個線程.成員聲明的順序必須使得線程在對象之前銷毀.如果無效破壞駐留在另一個線程中的對象.

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.

只有在以下斷言成立時才能安全地銷毀 QObject:

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

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

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

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

有人可能會爭辯說我們不打算"將我們的班級轉移到另一個線程.如果是這樣,那么顯然我們的對象不再是 QObject,因為 QObject 具有 moveToThread 方法并且可以隨時移動.如果一個類不遵守 Liskov 的替換原則到它的基類,這是一個錯誤從基類聲明公共繼承.因此,如果我們的類公開繼承自QObject,它必須允許自己隨時移動到任何其他線程.

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 在這方面有點異常.至少,它應該使 moveToThread 成為受保護的方法.

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();
}

這篇關于如何安全地銷毀 QThread?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!

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

相關文檔推薦

How can I read and manipulate CSV file data in C++?(如何在 C++ 中讀取和操作 CSV 文件數據?)
In C++ why can#39;t I write a for() loop like this: for( int i = 1, double i2 = 0; (在 C++ 中,為什么我不能像這樣編寫 for() 循環: for( int i = 1, double i2 = 0;)
How does OpenMP handle nested loops?(OpenMP 如何處理嵌套循環?)
Reusing thread in loop c++(在循環 C++ 中重用線程)
Precise thread sleep needed. Max 1ms error(需要精確的線程睡眠.最大 1ms 誤差)
Is there ever a need for a quot;do {...} while ( )quot; loop?(是否需要“do {...} while ()?環形?)
主站蜘蛛池模板: 无遮挡毛片 | 超碰人人插 | 国产三级在线看 | 久久av一区二区三区亚洲 | 特级淫片aaaaaaa级 | 一区二区三区国产精品 | 少妇高潮久久久久久潘金莲 | 欧美激情第二页 | 亚洲精品视频在线观看免费 | 性色av蜜臀av浪潮av老女人 | 亚洲一区二区欧美 | 亚洲欧美日韩国产精品 | 麻豆91视频| 亚洲免费成人 | 黄色片免费 | 神马午夜视频 | 国产精品久久久久久亚洲影视 | 国产激情久久 | 久热久草 | 亚洲天堂国产 | 欧美在线视频播放 | 亚洲日本国产 | 成人h片在线观看 | 日韩一区二区在线视频 | 欧美精品在线视频 | 激情高潮到大叫狂喷水 | 久久久久久中文字幕 | 欧美区日韩区 | 蜜桃色999 | 97国产在线 | 婷婷第四色 | 亚洲成人国产 | 日韩一区二区在线视频 | 99热最新 | 3p在线观看 | 一区免费视频 | 欧美午夜精品一区二区三区 | 国产视频99 | 日韩一区精品 | www.色中色 | 国产一区二区在线看 |