如何正确使用QThread

简介: 简述要实现一个线程很简单,写一个函数,绑定一些数据,如果有必要的话,可以使用 mutex 或者其他方法来保证和线程的安全交互。无论是 Win32、POSIX 或其他线程,工作原理都基本相同,并相当可靠。至少我敢说比 socket 更容易使用和处理。简述worker-objectworker-object使用 QThread 时,最主

简述

要实现一个线程很简单,写一个函数,绑定一些数据,如果有必要的话,可以使用 mutex 或者其他方法来保证和线程的安全交互。

无论是 Win32、POSIX 或其他线程,工作原理都基本相同,并相当可靠。至少我敢说比 socket 更容易使用和处理。

worker-object

使用 QThread 时,最主要的事情是把它当成一个线程对象的封装。此封装提供了信号、槽和方法,可以轻松地使用 Qt 项目中的线程对象。这说明了子类化 QThread 并实现其 run() 函数是非常错误的。

一个 QThread 应该更像一个普通线程实例:准备一个 QObject 类和所有想要的功能,然后创建一个新的QThread,使用 moveToThread(QThread *) 将 QObject 对象移动至线程中,并调用 QThread 实例的 start() 函数。就这样,再设置适当的信号/槽连接使它正常退出,所有的事情就都做完了。

实现一个简单的 Worker 类:

class Worker : public QObject {
    Q_OBJECT

public:
    Worker();
    ~Worker();

public slots:
    void process();

signals:
    void finished();
    void error(QString err);

private:
    // 在此处添加变量
};

至少需要添加一个共有的槽函数,用于触发实例,一旦线程开启,就立刻处理数据。

现在,看看这个类的基本实现:

Worker::Worker() {
    // 这里,可以从构造函数参数拷贝数据到内部变量
}

Worker::~Worker() {
    // 释放资源
}

// 开始处理数据
void Worker::process() {
    // 这里,使用新分配资源
    qDebug("Hello World!");
    emit finished();
}

虽然 Worker 类没有做什么特别的事情,但它包含了所有必需的元素。当其主函数(这种情况下,是 process())被调用,就立即开始处理数据。当处理完成以后,会发射 finished() 信号,将被用来触发 QThread 实例的退出。

顺便说一句,这里需要注意的一个极为重要的事情 - 永远不应该在 QObject 类的构造函数中使用堆对象(new)。因为分配之后,会在主线程上执行,而非 QThread 实例。这意味着新创建的对象由主线程所拥有,而非 QThread 实例,这将使你的代码无法正常工作。相反,在这种情况下,在主函数(process())中分配这些资源,当被调用时,对象将会在新线程实例中。因此,它将拥有资源。

现在,来看看如何通过创建一个新的 Worker 实例,并把它放在一个 QThread 实例中:

QThread *thread = new QThread();
Worker *worker = new Worker();
worker->moveToThread(thread);

// 错误处理
connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString)));

// 处理数据
connect(thread, SIGNAL(started()), worker, SLOT(process()));

// 退出、删除
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

// 启动线程
thread->start();

注意: connect() 系列是最为关键的部分。

当 worker 实例发出 finished() 信号时,线程就会退出。然后,使用相同的信号用于删除 worker。

为了防止讨厌的 crash(有可能当 thread 被删除时,还没有完全关闭),连接 thread(非 worker)的 finished() 信号到其自身的 deleteLater() 槽函数。这时,只有线程在完全退出时,才会被删除。

目录
相关文章
|
6月前
|
JavaScript Java 关系型数据库
基于springboot的社区垃圾分类管理系统
本系统基于Spring Boot与MySQL,结合物联网、大数据等技术,构建社区智能垃圾管理平台。实现垃圾投放监控、自动分类识别、积分激励及数据统计分析,提升管理效率与居民参与度,推动绿色社区可持续发展。
|
7天前
|
弹性计算 人工智能 Linux
阿里云服务器免费试用攻略:个人、企业免费云服务器配置与试用政策介绍
阿里云面向个人开发者与企业用户提供免费试用政策,助力零成本短期租用云服务器。个人用户完成实名认证后,可试用2核2GB至4核8GB等配置,最高300元额度;企业用户完成企业认证后,可享最高8核16GB配置,支持多地域灵活试用。试用需满足新用户、无欠费等条件,每人仅一次机会,不支持转让退款。此外,阿里云还提供超30款AI产品及7000万tokens免费体验,用户可先试后买,充分验证后再决策,有效降低上云门槛与成本。
|
2月前
|
数据采集 人工智能 搜索推荐
AI搜索时代的权衡:Geo优化中哪些是核心基石,哪些是次要干扰?
在生成式AI重塑搜索的今天,SEO正加速演进为GEO(生成式引擎优化)。本文基于麦肯锡2025报告与于磊专家实践,提出“两大核心”(人性化Geo、内容交叉验证)与“四轮驱动”(EEAT、结构化内容、关键词兼容、精准引用)方法论,厘清必须做与不必急做的关键边界,助力企业抢占AI搜索新入口。
173 2
|
2月前
|
消息中间件 缓存 编解码
私域直播系统搭建中的分层架构设计与模块解耦思路
私域直播系统易陷“越改越乱”困境:功能牵一发而动全身、上线周期长、性能瓶颈难定位。根因非代码质量,而在架构缺乏分层与解耦。本文详解五层架构(接入→应用→领域→基础设施→外部服务)与事件驱动、接口抽象、数据隔离三大解耦实践,助你构建高可维护、易扩展的直播系统。(239字)
|
Go API 开发者
Golang Websocket框架:实时通信的新选择
Golang Websocket框架:实时通信的新选择
|
数据安全/隐私保护
VirtualBox安装OpenEuler2
VirtualBox安装OpenEuler
189 0
|
编解码 数据可视化 搜索推荐
ffdshow源代码分析:解码、编码与多媒体处理的深度探索
ffdshow是知名的DirectShow解码器,集成多种视频音频解码器如libavcodec、libmpeg2等,支持格式丰富。它提供滤镜处理(如锐化、亮度调节)和可视化效果,允许用户个性化设置。此外,ffdshow处理音频,支持AC3、MP3等格式,可外挂DSP插件增强音效。通过对源代码的分析,能深入了解其解码、处理机制,预示着ffdshow将持续改进以提升多媒体体验。
|
JSON 编解码 前端开发
阿里低代码引擎和生态建设实战及思考
阿里低代码引擎和生态建设实战及思考
4135 0
阿里低代码引擎和生态建设实战及思考
|
机器学习/深度学习 人工智能 编解码
基于ModelScope,视觉AI启动模型开放之路
计算机视觉是人工智能的基石之一,也是应用最广泛的AI技术,从日常手机解锁使用的人脸识别,再到火热的产业前沿自动驾驶,视觉AI都大显身手。作为一名视觉AI从业者,我认为视觉AI的潜能远未得到充分发挥,穷尽我们这些研究者的力量,也只能覆盖少数行业和场景,远未能满足全社会的需求。因此,在AI模型社区魔搭ModelScope上,我们决定全面开源达摩院研发的视觉AI模型,首批达101个,其中多数为SOTA或
1814 0
基于ModelScope,视觉AI启动模型开放之路
|
分布式计算 资源调度 安全
Hadoop Yarn RPC未授权访问漏洞
Hadoop Yarn RPC未授权访问漏洞
2285 0
Hadoop Yarn RPC未授权访问漏洞

热门文章

最新文章