百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

Qt中开启线程的五种方法

ztj100 2025-02-26 14:45 31 浏览 0 评论

简介

在开发过程中,使用线程是经常会遇到的场景,本篇文章就来整理一下 Qt 中使用线程的五种方式,方便后期回顾。前面两种比较简单,一笔带过了,主要介绍后面三种。最后两种方法博主最喜欢,不需要继承类,可以直接把需要执行的函数放到线程中去运行

1、继承 QThread 重写 run 函数

class Thread : public QThread
{
    Q_OBJECT
public:
	virtual void run() override;
}
void Thread::run()
{
	...
}
  • 可调用 thread.start()启动线程,会自动调用 run 函数
  • 可调用 thread.isRunning()判断线程是否已启动
  • 可调用 thread.terminate()终止线程
  • 可调用 thread.wait()等待线程终止

2、继承 QObject 调用 moveToThread

class Test : public QObject
{
    Q_OBJECT
public:
    void test();
}
QThread th;
Test test;
test.moveToThread(&th);

需要注意的是:此方法与继承 QThread 相比较,继承 QThread 只有 run 函数中的操作是在线程中执行的,而此方法中所有的成员函数都是在线程中执行

3、继承 QRunnable 重新 run 函数,结合 QThreadPool 实现线程池

#include 
#include 
#include 
#include 
#include 

class BPrint : public QRunnable
{
	void run()
	{
	    for ( int count = 0; count < 5; ++count )
	    {
			qDebug() << QThread::currentThread();
			QThread::msleep(1000);
	    }
	}
};

int main(int argc, char *argv[])
{
	QCoreApplication a(argc, argv);
 
	QThreadPool threadpool;	           		// 构建一个本地的线程池
	threadpool.setMaxThreadCount(3);        // 线程池中最大的线程数
	
    for ( int num = 0; num < 100; ++num )
	{
	    BPrint *print;    					// 循环构建可在线程池中运行的任务
	    threadpool.start(print);      		// 线程池分配一个线程运行该任务
	    QThread::msleep(1000);
	}
	
	return a.exec();
}

QT开发交流+赀料君羊:714620761

在上述例子当中,我们创建的 QRunnable 类型的指针 BPrint *print 是不需要我们手动去回收内存的,QThreadPool 在结束该任务的执行后会将对该内存进行清空

有的小伙伴会有疑问,既然有 QThread 线程类了,为啥还要用 QRunnable + QThreadPool 创建线程池的方法来使用线程机制呢,感觉用起来很麻烦啊。所以这里要说明一下此方法的使用场景,当线程任务量非常大的时候,如果频繁的创建和释放 QThread 会带来非常大的内存开销,而线程池则可以有效避免这个问题

还有一个问题需要注意一下,QThread 是集成自 QObject 的,我们通常会使用信号槽与外界进行通信。而 QRunnable 并不是继承自 QObject 类的,所以他无法使用信号槽机制进行通信。这里推荐两种方法,一个是使用 QMetaObject::invokeMethod()函数。另一个是使用多重继承的方法,自定义类需要同时继承自 QRunnable 和 QObject

4、使用 C++ 11 中的 sth::thread

#include 
void threadfun1()
{
    std::cout << "threadfun1 - 1\r\n" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "threadfun1 - 2" << std::endl;
}

void threadfun2(int iParam, std::string sParam)
{
    std::cout << "threadfun2 - 1" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(5));
    std::cout << "threadfun2 - 2" << std::endl;
}

int main()
{
    std::thread t1(threadfun1);
    std::thread t2(threadfun2, 10, "abc");
    t1.join();		// 等待线程 t1 执行完毕
    std::cout << "join" << std::endl;
    t2.detach();	// 将线程 t2 与主线程分离
    std::cout << "detach" << std::endl;
}

运行结果:
threadfun1 - 1
threadfun2 - 1

threadfun1 - 2
join
detach

根据输出结果可以得知,t1.join() 会等待t1线程退出后才继续往下执行,t2.detach() 并不会等待,detach字符输出后,主函数退出,threadfun2还未执行完成,但是在主线程退出后,t2的线程也被已经被强退出

5、Qt QtConcurrent 之 Run 函数

Concurrent 是并发的意思,QtConcurrent 是一个命名空间,提供了一些高级的 API,使得所写的程序可根据计算机的 CPU 核数,自动调整运行的线程数目。这意味着今后编写的应用程序将在未来部署在多核系统上时继续扩展

函数原型如下:

QFuture QtConcurrent::run(Function function, ...)

QFuture QtConcurrent::run(QThreadPool *pool, Function function, ...)

简单来说,QtConcurrent::run() 函数会在一个单独的线程中执行,并且该线程取自全局 QThreadPool,该函数的返回值通过 QFuture API 提供

需要注意的是:

1)该函数可能不会立即运行; 函数只有在线程可用时才会运行

2)通过 QtConcurrent::run() 返回的 QFuture 不支持取消、暂停,返回的 QFuture 只能用于查询函数的运行/完成状态和返回值

3) Qt Concurrent 已经从 QtCore 中移除并成为了一个独立的模块,所以想要使用 QtConcurrent 需要在 pro 文件中导入模块:

QT += concurrent

使用方式有以下几种:

1)将函数运行在某一个线程中,需要使用 extern

extern void func();
QFuture future = QtConcurrent::run(func);

2)向该函数传递参数

extern void FuncWithArguments(int arg1, const QString &string);

int integer = ...;
QString string = ...;
// 需要传递的参数,则跟在函数名之后,依次加入
QFuture future = QtConcurrent::run(FuncWithArguments, integer, string);	

3) 获取该函数的计算结果

extern QString Func(const QByteArray &input);

QByteArray byte_array = ...;
QFuture future = QtConcurrent::run(func, byte_array);
...
QString result = future.result();

4)常量成员函数

QByteArray bytearray = "hello world";
// 在一个单独的线程中,调用 QByteArray 的常量成员函数 split(),传递给 run() 函数的参数是 bytearray
QFuture< QList > future = QtConcurrent::run(bytearray, &QByteArray::split, ',');
...
QList result = future.result();

5)非常量成员函数

QImage image = ...;
// 在一个单独的线程中,调用 QImage 的非常量成员函数 invertPixels(),传递给 run() 函数的参数是 &image
QFuture future = QtConcurrent::run(&image, &QImage::invertPixels, QImage::InvertRgba);
...
future.waitForFinished();

6)Lambda 表达式

QT开发交流+赀料君羊:714620761

#include 
#include 
#include 

QThreadPool pool;
QFuture future = QtConcurrent::run(&pool, [&](QObject *receiver){
    cv::Mat mat = QYImageProcessing::convertQImageToMat(image);
    cv::Mat center = cv::imread("dynaPhase_center.png");
    
    dynaPhase_alive = QYImageProcessing::getDiffPoint(mat, center);
    
    // 根据三个点自适应模拟条纹
    cv::Mat ret = DynamicCarrier::DC_Adaptive_Simulation(dynaPhase_center, dynaPhase_alive, dynaPhase_align);
    ret = ret*255;
    ret.convertTo(ret, CV_8UC1);
    QImage adaptive = QYImageProcessing::convertMatToQImage(ret);
    
    QYAlignControl *align = static_cast(receiver);
    align->callQmlGetAlivePoint(adaptive, dynaPhase_alive.x, dynaPhase_alive.y);
}, this);

相关推荐

Vue3非兼容变更——函数式组件(vue 兼容)

在Vue2.X中,函数式组件有两个主要应用场景:作为性能优化,因为它们的初始化速度比有状态组件快得多;返回多个根节点。然而在Vue3.X中,有状态组件的性能已经提高到可以忽略不计的程度。此外,有状态组...

利用vue.js进行组件化开发,一学就会(一)

组件原理/组成组件(Component)扩展HTML元素,封装可重用的代码,核心目标是为了可重用性高,减少重复性的开发。组件预先定义好行为的ViewModel类。代码按照template\styl...

Vue3 新趋势:10 个最强 X 操作!(vue.3)

Vue3为前端开发带来了诸多革新,它不仅提升了性能,还提供了...

总结 Vue3 组件管理 12 种高级写法,灵活使用才能提高效率

SFC单文件组件顾名思义,就是一个.vue文件只写一个组件...

前端流行框架Vue3教程:17. _组件数据传递

_组件数据传递我们之前讲解过了组件之间的数据传递,...

前端流行框架Vue3教程:14. 组件传递Props效验

组件传递Props效验Vue组件可以更细致地声明对传入的props的校验要求...

前端流行框架Vue3教程:25. 组件保持存活

25.组件保持存活当使用...

5 个被低估的 Vue3 实战技巧,让你的项目性能提升 300%?

前端圈最近都在卷性能优化和工程化,你还在用老一套的Vue3开发方法?作为摸爬滚打多年的老前端,今天就把私藏的几个Vue3实战技巧分享出来,帮你在开发效率、代码质量和项目性能上实现弯道超车!一、...

绝望!Vue3 组件频繁崩溃?7 个硬核技巧让性能暴涨 400%!

前端的兄弟姐妹们五一假期快乐,谁还没在Vue3项目上栽过跟头?满心欢喜写好的组件,一到实际场景就频频崩溃,页面加载慢得像蜗牛,操作卡顿到让人想砸电脑。用户疯狂吐槽,领导脸色难看,自己改代码改到怀疑...

前端流行框架Vue3教程:15. 组件事件

组件事件在组件的模板表达式中,可以直接使用...

Vue3,看这篇就够了(vue3 从入门到实战)

一、前言最近很多技术网站,讨论的最多的无非就是Vue3了,大多数都是CompositionAPI和基于Proxy的原理分析。但是今天想着跟大家聊聊,Vue3对于一个低代码平台的前端更深层次意味着什么...

前端流行框架Vue3教程:24.动态组件

24.动态组件有些场景会需要在两个组件间来回切换,比如Tab界面...

前端流行框架Vue3教程:12. 组件的注册方式

组件的注册方式一个Vue组件在使用前需要先被“注册”,这样Vue才能在渲染模板时找到其对应的实现。组件注册有两种方式:全局注册和局部注册...

焦虑!Vue3 组件频繁假死?6 个奇招让页面流畅度狂飙 500%!

前端圈的朋友们,谁还没在Vue3项目上踩过性能的坑?满心期待开发出的组件,一到高并发场景就频繁假死,用户反馈页面点不动,产品经理追着问进度,自己调试到心态炸裂!别以为这是个例,不少人在电商大促、数...

前端流行框架Vue3教程:26. 异步组件

根据上节课的代码,我们在切换到B组件的时候,发现并没有网络请求:异步组件:...

取消回复欢迎 发表评论: