本文将对Qt中使用线程的五种方式进行梳理,以备后期回顾。前两个比较简单,拍了一段时间了。主要介绍后三种。感兴趣的朋友可以跟随边肖去看一看。
简介
目录
1。继承QThread,重写运行函数2。继承QObject并调用moveToThread3。继承QRunnable和re-run函数,结合QThreadPool实现线程池4。使用sth:thread5的run函数。C 11中的Qt QtConcurrent。
简介
在开发过程中,使用线程是常见的场景。本文将整理出Qt中使用线程的五种方式,以备日后回顾。前两个比较简单,不过简单提一下。主要介绍后三种。后两种方法是博主的最爱。它们不需要继承类,可以直接把要执行的函数放到线程中运行。
1. 继承 QThread 重写 run 函数
类线程:公共QThread
{
q _对象
公共:
虚拟void run()覆盖;
}
void线程:run()
{
.
}
可以调用thread.start()来启动线程,run函数会被自动调用。
可以调用thread.isRunning()来确定线程是否已经启动。
可以调用thread.terminate()来终止线程。
可以调用thread.wait()等待线程终止。
2. 继承 QObject 调用 moveToThread
类测试:公共对象
{
q _对象
公共:
void test();
}
QThread th
测试测试;
test . movetothread(th);
需要注意的是:与继承QThread相比,该方法继承的QThread在线程中只执行run函数中的操作,而该方法中的所有成员函数都在线程中执行。
3. 继承 QRunnable 重新 run 函数,结合 QThreadPool 实现线程池
#包含QObject
#包含QRunnable
#包含QThread
#包含QThreadPool
#包含QDebug
类BPrint : public QRunnable
{
无效运行()
{
for(int count=0;计数5;计数)
{
qDebug()q thread:current thread();
q thread:m sleep(1000);
}
}
};
int main(int argc,char *argv[])
{
QCoreApplication a(argc,argv);
QThreadPool线程池;//建立一个本地线程池
thread pool . setmaxthreadcount(3);//线程池中的最大线程数
for(int num=0;num 100数字)
{
BPrint * print//循环来构建可以在线程池中运行的任务
threadpool.start(打印);//线程池分配一个线程来运行此任务
q thread:m sleep(1000);
}
返回a . exec();
}
在上面的例子中,我们创建的QRunnable类型的指针BPrint *print不需要我们手动回收内存,QThreadPool会在完成这个任务的执行后清空内存。
有朋友会问,既然有QThread线程类,为什么用QRunnable QThreadPool创建线程池来使用线程机制呢?用起来感觉比较麻烦。因此,这里描述一下这种方法的使用场景。当线程任务量非常大的时候,频繁的创建和释放QThread会带来非常大的内存开销,线程池可以有效的避免这个问题。
还有一个问题需要注意。QThread与QObject集成在一起,我们通常使用信号槽与外界通信。QRunnable不从QObject类继承,所以不能使用信号槽机制进行通信。这里推荐两种方法。一种是使用QMetaObject:invokeMethod()函数。另一种是多重继承的方法。自定义类需要从QRunnable和QObject继承。
4. 使用 C++ 11 中的 sth::thread
#包含线程
void threadfun1()
{
STD:cout ' thread fun 1-1 \ r \ n ' STD:endl;
STD:this _ thread:sleep _ for(STD:chrono:seconds(1));
STD:cout ' thread fun 1-2 ' STD:endl;
}
void threadfun2(int iParam,std:string sParam)
{
STD:cout ' thread fun 2-1 ' STD:endl;
STD:this _ thread:sleep _ for(STD:chrono:seconds(5));
STD:cout ' thread fun 2-2 ' STD:endl;
}
int main()
{
std:线程t1(thread fun 1);
std:线程t2(threadfun2,10,' ABC ');
t1 . join();//等待线程t1完成执行
STD:cout ' join ' STD:endl;
T2 . detach();//将线程t2与主线程分开
STD:cout ' detach ' STD:endl;
}
运行结果:
线程功能1 - 1
线程功能2 - 1
线程功能1 - 2
加入
派遣
根据输出结果可以得知,t1.join()会等待一种网络的名称(传输率可达1.54mbps)级(一种通讯线路的名称)线程退出后才继续往下执行,t2.detach()并不会等待,分离字符输出后,主函数退出,线程2还未执行完成,但是在主线程退出后,t2的线程也被已经被强退出
5. Qt QtConcurrent 之 Run 函数
同时发生的是并发的意思,Qt并发是一个命名空间,提供了一些高级的API,使得所写的程序可根据计算机的中央处理器核数,自动调整运行的线程数目。这意味着今后编写的应用程序将在未来部署在多核系统上时继续扩展
函数原型如下:
QFutureT QtConcurrent:run(函数功能,)
QFutureT Qt concurrent:run(QThreadPool * pool,函数功能,)
简单来说,QtConcurrent:run()函数会在一个单独的线程中执行,并且该线程取自全局QThreadPool,该函数的返回值通过QFuture API提供
需要注意的是:
1)该函数可能不会立即运行;函数只有在线程可用时才会运行
2)通过QtConcurrent:run()返回的QFuture不支持取消、暂停,返回的QFuture只能用于查询函数的运行/完成状态和返回值
3)季度并发已经从QtCore中移除并成为了一个独立的模块,所以想要使用夸脱并发需要在赞成文件中导入模块:
QT=并发
使用方式有以下几种:
1)将函数运行在某一个线程中,需要使用 extern
外部void func();
QFuturevoid future=Qt concurrent:run(func);
2)向该函数传递参数
带参数的extern void函数(int arg 1,const QString string);
(同Internationalorganizations)国际组织整数=.
QString字符串=.
//需要传递的参数,则跟在函数名之后,依次加入
QFuturevoid future=Qt concurrent:run(func带参数,整数,字符串);
3)获取该函数的计算结果
extern QString Func(const QByteArray输入);
QByteArray byte_array=.
QFutureQString future=Qt concurrent:run(func,byte _ array);
.
QString结果=未来。结果();
4)常量成员函数
QByteArray bytearray=' hello world ';
//在一个单独的线程中,调用QByteArray的常量成员函数拆分(),传递给运行()函数的参数是bytearray
q future QListQByteArray future=Qt concurrent:run(bytearray,QByteArray:split,',');
.
QListQByteArray结果=未来。结果();
5)非常量成员函数
齐马格图像=.
//在一个单独的线程中,调用齐马格的非常量成员函数invertPixels(),传递给运行()函数的参数是图像
QFuturevoid future=Qt concurrent:run(image,QImage:invertPixels,QImage:invert rgba);
.
未来。waitforfinished();
6)Lambda 表达式
#包括QFuture
#包含夸脱并发
#包含q线程池
q线程池池;
QFuturevoid future=Qt concurrent:run(pool,[](QObject *receiver){
cv:Mat Mat=qyimage processing:convertQImageToMat(image);
cv:Mat center=cv:im read(' dyna phase _ center。png’);
dyna phase _ alive=qyimage processing:getDiffPoint(mat,center);
//根据三个点自适应模拟条纹
cv:Mat ret=动态运营商:DC _自适应_模拟(动态相位_中心,动态相位_活跃,动态相位_对齐);
ret=ret * 255
ret.convertTo(ret,CV _ 8uc 1);
QImage adaptive=qyimage processing:convertmattokimage(ret);
QYAlignControl * align=static _ castQYAlignControl *(receiver);
align-callQmlGetAlivePoint(adaptive,dynaPhase_alive.x,dynaPhase_alive。y);
},这个);
到此这篇关于夸脱中开启线程的五种方式的文章就介绍到这了,更多相关夸脱线程内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。