如何安全地销毁 QThread?

2024-04-23

我想正确地销毁一个QThread在 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();
}

我的问题是,最终我仍然得到:

QThread:线程仍在运行时被销毁


安全线索

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

它会表现得适当。

QObject 成员不需要位于堆上

另一个问题是Worker对象将会被泄露。不要将所有这些对象放在堆上,只需将它们设为成员即可MyClass或其 PIMPL。

成员声明的顺序是重要的,因为成员将在声明顺序相反。因此,析构函数MyClass将按顺序调用:

  1. m_workerThread.~Thread()至此,线程已完成并消失,并且m_worker.thread() == 0.

  2. m_worker.~Worker由于该对象是无线程的,因此在任何线程中销毁它都是安全的。

  3. ~QObject

因此,工作人员及其线程作为成员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

// 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成员。只有两种情况:

  1. If a QObject成员不会从类内移动到另一个线程,它必须是后裔班级的。

  2. 否则,我们must移动QObject另一个线程的成员。成员声明的顺序必须使得线程能够之前被摧毁物体。如果是invalid销毁驻留在另一个线程中的对象。

只有摧毁一个才是安全的QObject如果以下断言成立:

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

线程被破坏的对象将变成无线程的,并且!object->thread() holds.

有人可能会说我们不“打算”将我们的类移动到另一个线程。如果是这样,那么显然我们的对象不是QObject不再,自从QObjectmoveToThread方法,并且可以随时移动。如果一个类不遵守里氏替换原则 http://en.wikipedia.org/wiki/Liskov_substitution_principle对于其基类,从基类声明公共继承是错误的。那么如果我们班publicly继承自QObject, it must允许自己随时移动到任何其他线程。

The QWidget在这方面有点异常。至少,它应该使moveToThread受保护的方法。

例如:

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();
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何安全地销毁 QThread? 的相关文章

随机推荐

  • 当焦点位于输入字段时,为什么 React 中的日期选择器会闪烁?

    有人可以告诉我为什么当焦点位于输入字段时 React 中的 datepicker 会闪烁吗 我在我的演示中使用这个日期选择器 https www npmjs com package semantic ui calendar react bu
  • RESTful服务中的资源级授权

    Let users id 是 RESTful 服务中的资源 url 启用基本身份验证 仅允许经过身份验证的用户访问该 url 示例场景 User 1 User 2是通过 userId 1 和 2 进行身份验证的用户 由于两者都经过身份验证
  • 如何控制图库图像的重叠?

    我正在从 URL 下载图像并将它们放入图库中 下载图像后 它们会正确加载 一旦从缓存加载图像 图像就会相互重叠 我该如何解决这个问题 Use the android spacing图库视图的属性
  • 如何捕获预期(和预期)的 302 Ajax 响应?

    所以 如果你回头看看我的上一个问题 https stackoverflow com questions 2764444 getting autodiscover url from exchange email address关于 Excha
  • 如何通过单击 MainFrame 内的按钮来更改 MFC 视图

    我想通过单击窗口内的按钮来更改呈现的视图像这样 https i stack imgur com 3IA2o png 我的项目设置 我制作了一个没有文档 视图支持的 MFC 项目 SDI 我在设计器中又创建了两个视图并向它们添加了类 新的视图
  • 使用 MultiIndex 列过滤行

    当创建具有 MultiIndex 列的 DataFrame 时 似乎无法使用类似语法来选择 过滤行df df AA gt 0 0 例如 import pandas as pd import numpy as np dates np asar
  • 如何让 Icecast 在端口 80 上运行 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我在尝试让 Icecast 在端口 80 上工作时遇到问题 它在默认情况下工作 但当我尝试将其设置为端口 80 时 一切都中断了 我已确保
  • 错误例如:“求解环境:初始冻结求解失败。使用“灵活解决”和“单元测试”选项卡重试

    我正在使用spyder python 我想测试我的代码 我已遵循pip install spyder unittest and pip install pytest 我已经重新启动了内核并重新启动了我的 MAC 然而 单元测试选项卡不会出现
  • 如何使用 jquery 旋转悬停图像?

    我试图在悬停时将 返回顶部 按钮旋转 360 度 而在鼠标离开时不取消旋转 我已经尝试了多种 jQuery 代码变体 但我似乎仍然无法让它工作 这是迄今为止我所得到的真实示例 CSS 悬停在图像之间 我尝试将 jQuery 更改为mouse
  • Rails 3:更改现有 mysql 数据库的字符集和排序规则

    是否可以使用 Rails 迁移或其他选项更改现有 Mysql 数据库的字符集和排序规则 初始配置数据库字符集和排序规则的最佳方法是什么 本机查询可以在 Rails 迁移中执行 def self up execute ALTER DATABA
  • 如何使用linq动态过滤子集合

    我正在尝试过滤用户请求的结果 例如你有orders and order details and products是子集合 当用户想要按产品过滤时 我收到错误 因为No property or field PRODUCTS exists in
  • 如何在 FastAPI 中访问端点视图函数内的 APP 属性?

    这是我的项目结构 gitignore README md requirements txt start py app main py apis v1 init py routes evaluation essentials py train
  • python pandas 选择头部和尾部

    对于 Pandas 中的 DataFrame 如何同时选择前 5 个值和后 5 个值 例如 In 11 df Out 11 A B C 2012 11 29 0 0 0 2012 11 30 1 1 1 2012 12 01 2 2 2 2
  • 无法将“obj\Debug\{project}.dll”复制到“bin\{project}.dll”

    最近 当我尝试运行我的项目时 Web 版 Visual Studio Express 2013 经常抛出此错误 我找到的唯一解决方案是退出并重新启动 Visual Studio 或 有时 完全重新启动 Windows 什么会导致这样的事情
  • 加载时css3过渡动画?

    是否可以在页面加载时使用 CSS3 过渡动画而不使用 Javascript 这就是我想要的 但是在页面加载时 图像滑块 html https web archive org web 20141021062316 http rilwis go
  • Spring Boot x509 测试 - pcf

    In 云铸造厂我已对其进行配置 以便将客户端证书转发到我的 Spring Boot 应用程序 该证书被放置在x forwarded client certheader 中 spring boot 应用程序读取 this 并检查 CN 是否已
  • 如何在access中查看宏代码?

    我有一个 Microsoft Access 数据库 里面有一个宏 如何查看宏的代码 打开Access数据库 您将看到表 查询 报告 模块和宏 其中包含可用于按顺序调用常见 MS Access 操作的宏 对于自定义 VBA 宏 请按 ALT
  • Safari 在 div 中使用 Google 地图打破边框半径

    对我来说关于 Stack 的第一个问题 我已经完成了我的作业并发现了类似这个主题的内容 在 webkit 浏览器中 v3 谷歌地图不尊重容器的边框半径 有人有解决方法吗 https stackoverflow com questions 1
  • 查找API端点的方法

    API探索 尽管有几个问题涉及该主题 但我找不到解决我想要理解的核心概念的问题 如果知道 API 的根结构 我们可以想象一下http stackoverflow com api service 我们可以成功地从已知端点检索结果 比方说htt
  • 如何安全地销毁 QThread?

    我想正确地销毁一个QThread在 Qt 5 3 中 到目前为止我已经得到 MyClass MyClass QObject parent QObject parent mThread new QThread this QObject con