目录
一、QTConcurrent是用于做什么的?
二、单线程示例Single Threaded
三、多线程示例Multi-Threaded
1. 新建线程——run
2. 获取返回值——QFuture
3. 信号槽使用——QFutureWatcher
4. 调用成员函数——run
QT官方文档[5.12.0]
- The QtConcurrent namespace provides high-level APIs that make it possible to write multi-threaded programs without using low-level threading primitives such as mutexes, read-write locks, wait conditions, or semaphores. Programs written with QtConcurrent automatically adjust the number of threads used according to the number of processor cores available. This means that applications written today will continue to scale when deployed on multi-core systems in the future.
- QtConcurrent includes functional programming style APIs for parallel list processing, including a MapReduce and FilterReduce implementation for shared-memory (non-distributed) systems, and classes for managing asynchronous computations in GUI applications:
QtConcurrent(并发)是一个命名空间,提供一些关于多线程的高级API。
简单来说就是搞多线程用的,与低级的那些方法相比更为方便。
写个方法,用来数数,1秒数一个
#include "mainwindow.h"
#include
#include
#include
using namespace Qt;
void getCount();
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//MainWindow w;
//w.show();
qDebug()<<"start"<
输出结果:
/* start 0 1 2 3 4 end */
从start到end中间是要等待的,也就是说getcount()方法没结束时,是无法运行后面代码的。
使用concurrent需要在pro项目文件中加入代码行,并添加头文件。
代码示例
#include "mainwindow.h"
#include
#include
#include
#include
using namespace Qt;
void getCount();
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//MainWindow w;
//w.show();
qDebug()<<"start"<
运行结果:
/* start end 0 1 2 3 4 */
因为getCount()丢给了新线程,原线程可以跳过等待直接运行后面的语句。
QT官方文档[6.5.2]
- QFuture allows threads to be synchronized against one or more results which will be ready at a later point in time. The result can be of any type that has default, copy and possibly move constructors. If a result is not available at the time of calling the result(), resultAt(), results() and takeResult() functions, QFuture will wait until the result becomes available. You can use the isResultReadyAt() function to determine if a result is ready or not. For QFuture objects that report more than one result, the resultCount() function returns the number of continuous results. This means that it is always safe to iterate through the results from 0 to resultCount(). takeResult() invalidates a future, and any subsequent attempt to access result or results from the future leads to undefined behavior. isValid() tells you if results can be accessed.
- QFuture provides a Java-style iterator (QFutureIterator) and an STL-style iterator (QFuture::const_iterator). Using these iterators is another way to access results in the future.
- If the result of one asynchronous computation needs to be passed to another, QFuture provides a convenient way of chaining multiple sequential computations using then(). onCanceled() can be used for adding a handler to be called if the QFuture is canceled. Additionally, onFailed() can be used to handle any failures that occurred in the chain. Note that QFuture relies on exceptions for the error handling. If using exceptions is not an option, you can still indicate the error state of QFuture, by making the error type part of the QFuture type. For example, you can use std::variant, std::any or similar for keeping the result or failure or make your custom type.
int getCount(int n);
//这里我们传参数4
QFuture f = QtConcurrent::run( getCount,4);
代码示例
#include "mainwindow.h"
#include
#include
#include
#include
using namespace Qt;
int getCount(int n);
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//__FUNCTION__ 得到当前运行的函数名称
//QThread::currentThread()当前线程标识
qDebug() << __FUNCTION__ << QThread::currentThread();
QFuture f = QtConcurrent::run( getCount,4);
// 会阻塞线程
qDebug()<< "f.result: "<
运行结果:
/*
qMain QThread(0x25f41186dd0)
getCount QThreadPoolThread(0x25f42b0a430, name = "Thread (pooled)")
0 1 2 3
f.result: 4
f.resultCount: 1
end
*/
若需要频繁的创建线程,建议使用线程池。线程池可以维护一定数量的线程,只需要向线程池中丢任务就行,线程池会根据自己可使用线程数进行任务调度。
可以理解为多个窗口服务,只排一个队列,当有窗口空闲时,队列第一个人过去办理事务;线程池就是这个办事单位,它维护的线程数量就是窗口数量,任务就是排队的人。
来源:Qt线程池_贝勒里恩的博客-CSDN博客
代码示例
#include
#include
#include
#include
#include
int getCount(int n){ // 有参有返回
qDebug() << "进程池进程开始,当前线程标识:" << QThread::currentThread ();
int i = 0;
while (i < n) {
qDebug() << i;
Sleep(1000);
++i;
}
qDebug() << "进程池进程开始,当前线程标识:" << QThread::currentThread ();
return n;
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qDebug() << "主进程前,当前线程标识:" << QThread::currentThread ();
QFuture f = QtConcurrent::run( getCount, 4 );
//创建监视器w
QFutureWatcher w;
//将w设置监视线程结果f
w.setFuture (f);
QObject::connect (&w,&QFutureWatcher::finished,[&]{
qDebug()<< "[进程监视] 当前进程:"<< QThread::currentThread ();
qDebug()<< "[进程监视] 当前进程输出:" <
运行结果:
/*
主进程前,当前线程标识: QThread(0x1dcfc5e6dd0)
主进程后,当前线程标识: QThread(0x1dcfc5e6dd0)
进程池进程开始,当前线程标识: QThreadPoolThread(0x1dcfddca040, name = "Thread (pooled)")
0
1
2
3
进程池进程开始,当前线程标识: QThreadPoolThread(0x1dcfddca040, name = "Thread (pooled)")
[进程监视] 当前进程: QThread(0x1dcfc5e6dd0)
[进程监视] 当前进程输出: 4 1
*/
代码示例
#include
#include
#include
#include
#include
class Test{ // 声明一个类
public:
int getCount(int n){
qDebug() << "进程池进程开始,当前线程标识:" << QThread::currentThread ();
int i = 0;
while (i < n) {
qDebug() << i;
Sleep(1000);
++i;
}
qDebug() << "进程池进程开始,当前线程标识:" << QThread::currentThread ();
return n;
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qDebug() << "主进程前,当前线程标识:" << QThread::currentThread ();
Test test;
//QT5写法:QFuture f = QtConcurrent::run( &test, &Test::getCount, 4 );
//QT6
QFuture f = QtConcurrent::run( &Test::getCount, &test, 4 );
QFutureWatcher w;
w.setFuture (f);
QObject::connect (&w,&QFutureWatcher::finished,[&]{
qDebug()<< "[进程监视] 当前进程:"<< QThread::currentThread ();
qDebug()<< "[进程监视] 当前进程输出:" <
运行结果同上。
参考文章:
Qt 之 Concurrent 4、【例】并发函数Run用法示例_qtconcurrent::run_hitzsf的博客-CSDN博客
Qt QtConcurrent之 Run 函数用法_qtconcurrent::run_不脱发的码农~~~~的博客-CSDN博客
QtConcurrent多线程 - run()与QFuture_qtconcurrent::run-CSDN博客
感谢前辈们提供的经验( •̀ ω •́ ) ✧让我一个小菜鸡也能慢慢朝前爬