pbootcms网站模板|日韩1区2区|织梦模板||网站源码|日韩1区2区|jquery建站特效-html5模板网

如何安全地銷毀 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 ()?環形?)
主站蜘蛛池模板: 空气能暖气片,暖气片厂家,山东暖气片,临沂暖气片-临沂永超暖通设备有限公司 | 扒渣机,铁水扒渣机,钢水扒渣机,铁水捞渣机,钢水捞渣机-烟台盛利达工程技术有限公司 | 半自动预灌装机,卡式瓶灌装机,注射器灌装机,给药器灌装机,大输液灌装机,西林瓶灌装机-长沙一星制药机械有限公司 | 智能终端_RTU_dcm_北斗星空自动化科技 | RV减速机-蜗轮蜗杆减速机-洗车机减速机-减速机厂家-艾思捷 | 视频教程导航网_视频教程之家_视频教程大全_最新视频教程分享发布平台 | 吸音板,隔音板,吸音材料,吸音板价格,声学材料 - 佛山诺声吸音板厂家 | BAUER减速机|ROSSI-MERSEN熔断器-APTECH调压阀-上海爱泽工业设备有限公司 | 电伴热系统施工_仪表电伴热保温箱厂家_沃安电伴热管缆工业技术(济南)有限公司 | 六维力传感器_三维力传感器_二维力传感器-南京神源生智能科技有限公司 | 北京网络营销推广_百度SEO搜索引擎优化公司_网站排名优化_谷歌SEO - 北京卓立海创信息技术有限公司 | 酒瓶_酒杯_玻璃瓶生产厂家_徐州明政玻璃制品有限公司 | 2-羟基泽兰内酯-乙酰蒲公英萜醇-甘草查尔酮A-上海纯优生物科技有限公司 | 铝箔袋,铝箔袋厂家,东莞铝箔袋,防静电铝箔袋,防静电屏蔽袋,防静电真空袋,真空袋-东莞铭晋让您的产品与众不同 | 天津拓展_天津团建_天津趣味运动会_天津活动策划公司-天津华天拓展培训中心 | 蜘蛛车-登高车-高空作业平台-高空作业车-曲臂剪叉式升降机租赁-重庆海克斯公司 | 舞台木地板厂家_体育运动木地板_室内篮球馆木地板_实木运动地板厂家_欧氏篮球地板推荐 | 南京租车,南京汽车租赁,南京包车,南京会议租车-南京七熹租车 | 广州中央空调回收,二手中央空调回收,旧空调回收,制冷设备回收,冷气机组回收公司-广州益夫制冷设备回收公司 | 超声波电磁流量计-液位计-孔板流量计-料位计-江苏信仪自动化仪表有限公司 | 北京亦庄厂房出租_经开区产业园招商信息平台 | 塑料异型材_PVC异型材_封边条生产厂家_PC灯罩_防撞扶手_医院扶手价格_东莞市怡美塑胶制品有限公司 | 别墅图纸超市|别墅设计图纸|农村房屋设计图|农村自建房|别墅设计图纸及效果图大全 | 烟雾净化器-滤筒除尘器-防爆除尘器-除尘器厂家-东莞执信环保科技有限公司 | 厦门ISO认证|厦门ISO9001认证|厦门ISO14001认证|厦门ISO45001认证-艾索咨询专注ISO认证行业 | 耐高温风管_耐高温软管_食品级软管_吸尘管_钢丝软管_卫生级软管_塑料波纹管-东莞市鑫翔宇软管有限公司 | 南溪在线-南溪招聘找工作、找房子、找对象,南溪综合生活信息门户! | 耐酸碱胶管_耐腐蚀软管总成_化学品输送软管_漯河利通液压科技耐油耐磨喷砂软管|耐腐蚀化学软管 | 大白菜官网,大白菜winpe,大白菜U盘装系统, u盘启动盘制作工具 | 能量回馈_制动单元_电梯节能_能耗制动_深圳市合兴加能科技有限公司 | 昆明网络公司|云南网络公司|昆明网站建设公司|昆明网页设计|云南网站制作|新媒体运营公司|APP开发|小程序研发|尽在昆明奥远科技有限公司 | 杭州月嫂技术培训服务公司-催乳师培训中心报名费用-产后康复师培训机构-杭州优贝姆健康管理有限公司 | 泰国试管婴儿_泰国第三代试管婴儿费用|成功率|医院—新生代海外医疗 | MVR蒸发器厂家-多效蒸发器-工业废水蒸发器厂家-康景辉集团官网 | 切铝机-数控切割机-型材切割机-铝型材切割机-【昆山邓氏精密机械有限公司】 | 西安烟道厂家_排气道厂家_包立管厂家「陕西西安」推荐西安天宇烟道 | 环氧乙烷灭菌器_压力蒸汽灭菌器_低温等离子过氧化氢灭菌器 _低温蒸汽甲醛灭菌器_清洗工作站_医用干燥柜_灭菌耗材-环氧乙烷灭菌器_脉动真空压力蒸汽灭菌器_低温等离子灭菌设备_河南省三强医疗器械有限责任公司 | 德国GMN轴承,GMN角接触球轴承,GMN单向轴承,GMN油封,GMN非接触式密封 | 世界箱包品牌十大排名,女包小众轻奢品牌推荐200元左右,男包十大奢侈品牌排行榜双肩,学生拉杆箱什么品牌好质量好 - Gouwu3.com | 碳钢法兰厂家,非标法兰,定制异型,法兰生产厂家-河北九瑞管道 | 【ph计】|在线ph计|工业ph计|ph计厂家|ph计价格|酸度计生产厂家_武汉吉尔德科技有限公司 |