QT多线程
1. 重写run()函数
使用线程步骤
- 包含相关的头文件:
#include <QThread>
- 创建一个继承自QThread的子类:
创建一个新的类,继承自QThread,并重写其run()函数。
在run()函数中编写多线程需要执行的代码。
class MyThread : public QThread
{
Q_OBJECT
public:
void run() override
{
// 在这里编写多线程需要执行的代码
}
};
- 创建并启动线程:
在界面或其他需要的地方,创建一个MyThread对象,并调用其start()函数来启动线程。
MyThread myThread;
myThread.start();
- 处理线程完成信号(可选):
如果需要在主线程中处理线程完成的信号,可以连接线程的finished()信号到相应的槽函数。
connect(&myThread, &MyThread::finished, this, &MyClass::onThreadFinished);
- 退出线程:
退出线程,停止底层的事件循环
//退出线程的工作函数
void QThread::exit(int returnCode = 0);
//调用线程退出函数之后,线程不会马上退出因为当前任务有可能还没有完成
void QThread::wait();
//等待任务完成,然后退出线程,一般情况会在exit()后面调用这个函数
常用函数
公有函数:
函数 | 功能 |
---|---|
bool isFinished() | 线程是否结束 |
bool isRunning() | 线程是正在运行 |
Priority priority() | 返回线程的优先级 |
void setPriority(Priority priority) | 设置线程的优先级 |
void exit(int returnCode = 0) | 退出线程的事件循环,退出码为returnCode,0表示成功退出,否则表示有误 |
bool wait(unsigned long time) | 阻止线程执行,直到线程结束(从run()函数返回),或等待时间超过time毫秒 |
信号
函数 | 功能 |
---|---|
void finished() | 在线程就要结束时发射此信号 |
void started() | 在线程开始执行,run()函数被调用之前发射此信号 |
代码示例:
#include <QThread>
#include <QDebug>
class MyThread : public QThread
{
public:
void run() override
{
qDebug() << "Thread started";
// 线程执行的逻辑代码
for (int i = 0; i < 5; ++i) {
qDebug() << "Thread running" << i;
sleep(1); // 线程暂停1秒
}
qDebug() << "Thread finished";
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MyThread thread;
thread.start(); // 启动线程
// 在主线程中进行其他操作
thread.wait(); // 等待线程执行完毕
return app.exec();
}
2. 使用 moveToThread()
方法和步骤:
- 在主线程中创建一个新的线程:通常使用 QThread 或其子类来创建一个新的线程对象。
- 创建新的任务类继承QObject类,创建成员函数处理相应逻辑
- 将要移动到新线程的对象的指针传递给 moveToThread() 函数,以便将该对象从当前线程中分离出来并移动到新线程中运行。
- 在新线程中执行对象的工作:在新线程中调用对象的 start() 函数,启动新线程并开始执行对象的工作。
// 1.创建任务类
MyObject *obj = new MyObject();
// 2.创建一个新的线程
QThread *thread = new QThread();
// 3.将任务类对象移动到新线程中运行
obj->moveToThread(thread);
// 连接线程的 started() 信号和对象的 doWork() 槽函数
connect(thread, &QThread::started, obj, &MyObject::doWork);
// 连接对象的 finished() 信号和线程的 quit() 和 deleteLater() 槽函数
connect(obj, &MyObject::finished, thread, &QThread::quit);//终止线程的事件循环,使线程退出
connect(obj, &MyObject::finished, obj, &MyObject::deleteLater);//在下一个事件循环中删除对象,确保对象在被使用完毕后被正确释放。
// 连接线程的 finished() 信号和线程的 deleteLater() 槽函数
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
// 启动新线程并等待它结束
thread->start();
thread->wait();
//第一种方式为传递父对象
//第二种方式为手动释放:
connect(this,&MainWindow::destroyed(),this,[=]()
{
thread->quit();
thread->wait();
thread->deleteLater();
});
3. 线程池
线程池是一种管理多个线程的机制,可以用于处理并发任务,提高程序性能和响应速度。
线程池可以预先创建一定数量的线程,并维护一个任务队列,当有任务到来时,线程池会从空闲线程中获取一个线程来执行任务,执行完毕后将该线程释放回线程池,等待下一个任务的到来。
常用函数
- globalInstance(); //获取全局线程池实例。
- setMaxThreadCount(int maxThreadCount); //设置线程池中线程的最大数量。
- start(QRunnable *runnable); //将一个任务对象添加到线程池中并开始执行任务。
- activeThreadCount(); //获取当前活动的线程数量。
- expiryTimeout(); //获取线程池的过期超时时间。
- setExpiryTimeout(int expiryTimeout); //设置线程池的过期超时时间。
- waitForDone(int msecs); //等待线程池中所有任务执行完毕,最多等待指定的时间。
- clear(); //清除线程池中所有任务,并等待任务的执行完成。
- tryStart(QRunnable *runnable); //尝试将一个任务对象添加到线程池中开始执行,如果没有空闲线程,则不执行任务。
- reserveThread(); //预留一个线程,即使没有任务,该线程也会一直存在。
- releaseThread(); //释放一个预留线程。
代码示例:
Qt 提供了 QThreadPool 类来实现线程池,QThreadPool管理和回收各个QThread对象
// 创建线程池对象
QThreadPool *pool = QThreadPool::globalInstance();
// 设置线程池中线程的最大数量
pool->setMaxThreadCount(4);
// 创建任务对象
MyTask *task1 = new MyTask();
MyTask *task2 = new MyTask();
MyTask *task3 = new MyTask();
// 将任务对象添加到线程池中
pool->start(task1);
pool->start(task2);
pool->start(task3);
//QThreadPool::globalInstance()->start(task);
//在程序中显式地使用了 new 运算符创建了一个线程池对象,需要在不再需要该对象时手动调用 delete 运算符来释放它。
//对于全局线程池对象,不需要手动释放,Qt会处理它的生命周期。
在使用 QThreadPool 时,还需要实现自定义的任务类,继承自 QRunnable,并重写 run() 方法,在其中编写具体的任务逻辑。
通过 start() 方法将任务对象添加到线程池中后,线程池会自动分配线程来执行任务。
//想要在任务对象里面使用QT提供的信号槽机制,需要继承QObject
class MyTask : public Qobject, public QRunnable
{
Q_OBJECT;
public:
explicit Mytask(QObject *parent = nullptr)
{
//任务执行完毕,该对象自动销毁
setAutoDelete(true);
}
void run() override
{
// 执行任务的具体逻辑
}
};
4. Qtconcurrent
QtConcurrent 是 Qt 提供的一个模块,提供了一种更高级的并发编程框,用于简化多线程编程和并发执行任务。
它基于函数式编程的理念,允许你以一种更加高级和直观的方式在多个线程中执行函数或者 Lambda 表达式。
主要功能:
QtConcurrent::run()
QtConcurrent::run() 函数是最简单的 QtConcurrent 使用方式,它可以在新线程中执行一个函数或者 Lambda 表达式。
void myFunction() {
// 在这里编写需要在新线程中执行的代码逻辑
}
// 在新线程中执行函数
QtConcurrent::run(myFunction);
QtConcurrent::map()
QtConcurrent::map() 函数可以对一个序列中的每个元素并行地执行一个函数,并返回结果序列。
这个函数类似于标准库中的 std::transform,但是可以并行执行。
QList<int> inputList = {1, 2, 3, 4, 5};
// 对序列中的每个元素执行函数,返回结果序列
QList<int> outputList = QtConcurrent::map(inputList, [](int value) {
return value * 2;
});
QtConcurrent::filter()
QtConcurrent::filter() 函数可以对一个序列中的元素并行地执行一个谓词函数,并返回满足条件的元素组成的序列。
QList<int> inputList = {1, 2, 3, 4, 5};
// 过滤序列中的元素,返回满足条件的元素组成的序列
QList<int> filteredList = QtConcurrent::filter(inputList, [](int value) {
return value % 2 == 0;
});
QtConcurrent::mapped() 和 QtConcurrent::filtered()
QtConcurrent::mapped() 和 QtConcurrent::filtered() 是对 map() 和 filter() 的延迟版本,它们返回一个 QFuture 对象,允许你延迟执行并发操作。
QList<int> inputList = {1, 2, 3, 4, 5};
// 延迟执行 map 操作
QFuture<int> future = QtConcurrent::mapped(inputList, [](int value) {
return value * 2;
});
// 获取结果
QList<int> outputList = future.results();