栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

【Qt】Qt多线程开发—QThread

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Qt】Qt多线程开发—QThread

文章目录

一、QThread的两种使用方法

(1-1)方法一(1-2)方法二 二、Qt线程运行的两种策略三、QThread的使用注意事项四、总结

一、QThread的两种使用方法

QThread是Qt中用于在多线程中运行代码的核心类,它是QObject的一个子类。

​ 关于QThread如何使用,Qt官方提供了两种方法:

(1-1)方法一

​ 步骤一:子类化QThread并重新实现run()。

​ 步骤二:然后创建子类的实例并调用start()成员函数运行线程。

如下代码片段:

class MyThread : public QThread {
private:
	void run() override {
	// 要在新线程中运行的代码
	}
};

MyThread *thread = new MyThread;
thread->start(); // 调用run()启动一个新线程
// ...
thread->wait(); // 等待线程完成

线程具有优先级,在调用start()的时候可以指定优先级参数,或使用setPriority()更改线程的优先级。
​当从run()返回时(一段时间后)线程将停止运行,具体的时间长短与操作系统相关。

​QThread::isRunning()和QThread::isFinished()提供关于线程执行的信息,在开发中,可以通过这两个成员函数获取到线程的运行状态。

QThread提供了QThread::started()(当线程开始时发射)和QThread::finished()(在线程运行结束后发射)两个信号。

​一个线程可以通过调用QThread:sleep()函数临时停止执行。通常这是一个不好的使用方法,但是比事件驱动(或轮询)要好得多。

​通过QThread调用wait()来等待线程执行完成,可选择性向该函数传递等待的最大毫秒数。

(1-2)方法二

​ 第二种使用QThread创建、管理线程的方法:本质上不是派生QThread,而是对象关联。步骤如下:
(1)创建QThread。
(2)使用moveToThread()将对象添加到QThread管理的线程中运行。
如下代码片段:

auto thread = new QThread;

auto worker = new Worker;

connect(thread, &QThread::started, worker, &Worker::doWork);
connect(worker, &Worker::workDone, thread, &QThread::quit);

connect(thread, &QThread::finished, worker, &Worker::deleteLater);

worker->moveToThread(thread);
thread->start();

​ QThread的第二种使用方法,允许我们在多线程中运行代码而不需要子类化QThread。

二、Qt线程运行的两种策略

​ 在线程中运行代码有两种基本策略:不带事件循环和带事件循环

​ (1)不带事件循环

​ 派生类QThread并重载QThread::run()成员函数。创建一个实例并使用QThread::start()启动新线程。

class MyThread : public QThread {
private:
	void run() override {
		loadFilesFromDisk();
		doCalculations();
		saveResults();
	}
};
auto thread = new MyThread;
thread->start();

thread->wait();

​ (2)带事件循环

​ 当在处理定时器、网络、排队信号/槽链接等问题时,事件循环是必须的。

​ Qt支持单个线程的事件循环,如下图所示:

​ 每个线程的本地事件循环都为存在于该线程中的QObjects交付事件,如果没有事件循环,存在于对应线程中的对象将接收不到事件。

​ 通过在run()中调用QThread::exec()来启动线程的本地事件循环。如下代码片段:

class MyThread : public QThread {
private:
	void run() override {
    auto socket = new QTcpSocket;
    socket->connectToHost(...);

    exec(); // 运行事件循环

	// 执行一些清除操作
    }  
};

​ QThread::quit()或QThread::exit()将退出事件循环。可以使用QEventLoop或者手动调用QCoreApplication::processEvents()。

​ 注:QThread::run()的默认实现实际上调用了QThread: exec ()。如果重载了QThread::run(),我们就必须手动调用QThread: exec ()。

三、QThread的使用注意事项

​ 在非主线程中不能执行以下四种类型的操作:

(1)不能执行对GUI 控件的操作。包括但不限于:使用任何QWidget / Qt Quick / QPixmap API。这些情况是除外:使用QImage, QPainter等;使用OpenGL可能是可以的:但是需要在运行时调用QOpenGLContext: supportsThreadedOpenGL ()事先检查。

(2)不能调用Application::exec()。

(3)在销毁相应QThread对象之前,一定要销毁次要线程中的所有QObject。【这一点非常重要】。

(4)不要阻塞GUI线程。

​ 如何确保QObjects的被销毁?如下:

​ (1)在QThread::run()堆栈上创建QObject。

​ (2)将他们的QObject::deleteLater()槽函数连接到QThread::finished()信号。

​ (3)把QObject从线程里移出来。

​ 例如以下代码片段:

class MyThread : public QThread {
private:
	void run() override {
		MyQObject obj1, obj2, obj3;

		QScopedPointer p;
		if (condition)
			p.reset(new OtherQObject);

		auto anotherObj = new AnotherQObject;
		connect(this, &QThread::finished,anotherObj, &QObject::deleteLater);

		auto yetAnother = new YetAnotherQObject;

        // 在退出线程之前,将该对象移动到主线程中  
        yetAnother->moveToThread(qApp->thread());
        // 从这一行代码后,就不要使用或操作到这个QObject! 
	}
};
四、总结

Qt下多线程的开发,使用QThread比较方便。本文记录了使用QThread的两种方法,以及QThread中线程运行的事件交付方式,也记录关于QThread的一些注意事项。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/737792.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号