QT多线程之QtConcurrent::run()
QT有几种可以实现多线程编程的方式,其中最方便使用,最便携的一定是QtConcurrent::run()了,这是一个模板函数,有很多的重载原型。
//在新的线程中调用普通函数
template <typename T> QFuture<T> QtConcurrent::run(Function function, ...)
//使用线程池中的线程调用普通函数
template <typename T> QFuture<T> QtConcurrent::run(QThreadPool *pool, Function function, ...)
//在新的线程里调用成员函数 有多个重载实现不同的参数个数
template <typename T> QFuture<T> QtConcurrent::run(className *obejct, Function function, ...)
这些模板都有多个重载,支持带参数函数,切可以带多个参数。
QFuture 也是一个模板类,它可以监控线程的运行状态有,并可以获取在另一个线程中运行的函数的返回值,返回值通过调用result()函数获取。
需要注意的是获取返回值之前,最好先调用waitForFinished()保证线程执行完毕。
示例
QtThreadTest.h
#pragma once
#include <QtCore/QObject>
#include <QtConcurrent/QtConcurrent>
#include <QtCore/QThread>
class ThreadTest
{
public:
ThreadTest();
~ThreadTest() = default;
public:
void anotherThread();
std::string anotherThreadReturn();
};
QtThreadTest.cpp
#include "QtThreadTest.h"
#include <iostream>
#include <QFuture>
void normalFunction()
{
std::cerr << "Normal function thread ID: " << QThread::currentThreadId() << std::endl;
}
ThreadTest::ThreadTest()
{
std::cerr << "main thread ID: " << QThread::currentThreadId() << std::endl;
QtConcurrent::run(normalFunction);
QFuture<void> future = QtConcurrent::run(this, &ThreadTest::anotherThread);
QFuture<std::string> future1 = QtConcurrent::run(this, &ThreadTest::anotherThreadReturn);
future.waitForFinished();
future1.waitForFinished();
std::cerr << "anotherThreadReturn result: " << future1.result() << std::endl;
}
void ThreadTest::anotherThread()
{
std::cerr << "Another thread ID: " << QThread::currentThreadId() << std::endl;
}
std::string ThreadTest::anotherThreadReturn()
{
std::cerr << "Another return thread ID: " << QThread::currentThreadId() << std::endl;
return "This is result";
}
输出结果:
总结
- 调用run() 之后,函数不一定会被立即执行,如果有多个run()被调用,函数的调用顺序不一定是run()的调用顺序,这些都和线程的调度有关系。
- run(function) 实际上等价于run(QThreadPool::globalInstance(),function)
如果只是简单的想在其他线程中调用某个函数,不需要复杂的数据同步,那么QtConcurrent::run() 相比其他实现多线程的方式绝对是不二之选。
2022-11-1 补充
之前因为看漏了文档,导致今天被自己坑了一把。
文档中提到,Run中的函数参数,都是拷贝之后使用副本,如果在线程中调用的函数参数类型是引用类型,那么是不能正常对原有的变量进行改变的。
比如下面的例子
void refrencesPar(int& a, int& b)
{
a = 1;
b = 1;
std::cerr << "call refrencesPar() " << "a : " << a << ",b: " << b <<
" |a address:" << &a << " |b address: " << &b <<std::endl;
}
ThreadTest::ThreadTest()
{
int a = 0, b = 0;
auto future = QtConcurrent::run(refrencesPar, a, b);
future.waitForFinished();
std::cerr << "a : " << a << ",b: " << b <<" |a address:" << &a << " |b address: " << &b << std::endl;
}
运行代码输出的结果:
可以看到,两次输出的a,b变量的地址是不一样的,因为run在调用函数之前已经拷贝了一份副本,所以如果想在函数中改变外面变量的值,这里只能使用指针。