简介:
线程是操作系统中的基本执行单元,是一个独立的执行路径。每个线程都有自己的栈空间,用于存储本地变量和函数调用的上下文。多个线程可以在同一进程中并发执行,从而实现并发处理,提高程序的性能和响应能力。
与进程不同的是,线程是轻量级的,它们共享同一进程的地址空间,这意味着它们可以访问相同的内存和文件资源,从而更容易地共享数据和通信
线程类型:
1、QThread。
2、QObject+moveToThread实现。
3、QThreadPool+QRunnable实现。
4、QFuture+QtConcurrent实现。
5、std::thread实现,不是QT自身的,但是在Qt中使用比较方便也介绍下。
QThread:
介绍:优点是简单易用,能轻松地创建和管理线程。它提供了一些方法来控制线程的生命周期,包括start()和quit()方法来启动和停止线程,以及wait()方法来等待线程完成。
QThread还提供了一些信号来管理线程。例如,finished()信号在线程完成执行后发出,error()信号在线程发生错误时发出。它的线程入口是从run函数开始。
但是它也存在缺点,它只有run函数内部才是在线程范围内,其它函数都是在主线程中。
适用场景:生命周期长但是交互少的场景。
代码:
.h
#include <QThread>
class MThread : public QThread
{
Q_OBJECT
public:
MThread();
void run();
public slots:
void test(int val);
};
.cpp
#include "mthread.h"
#include <QDebug>
MThread::MThread()
{
qDebug()<<"main thread"<<QThread::currentThreadId();
}
void MThread::test(int val)
{
qDebug()<<"test val"<<QThread::currentThreadId()<<val;
}
void MThread::run()
{
qDebug()<<"thread 1"<<QThread::currentThreadId();
}
调用
MThread *thread = new MThread();
connect(this,&Widget::sigSendVal,thread,&MThread::test);
thread->start();
this->sigSendVal(66);
thread->wait();
thread->exit();
结果:
QObject+moveToThread实现:
介绍:优点是交互灵活,且跟主线程之间的所有信号槽都是在线程中执行,QThread拥有的线程控制它都具有,如start,quit,wait等等。
缺点:代码逻辑较复杂,使用灵活性没有那么高,由于创建的类较多,内存占用较高,性能相对较低。
适用场景:生命周期长,交互频繁且需要交互逻辑也在线程中的场景。
代码:
.h
#include <QObject>
class MThreadObject : public QObject
{
Q_OBJECT
public:
MThreadObject();
public slots:
void startThread();
void slotTest(int val);
};
};
.cpp
#include "mthreadobject.h"
#include <QThread>
#include <QDebug>
MThreadObject::MThreadObject()
{
qDebug()<<"main thread"<<QThread::currentThreadId();
}
void MThreadObject::startThread()
{
qDebug()<<"thread 2"<<QThread::currentThreadId();
}
void MThreadObject::slotTest(int val)
{
qDebug()<<"test val"<<QThread::currentThreadId()<<val;
}
调用
MThreadObject* object = new MThreadObject();
QThread* thread2 = new QThread;
object->moveToThread(thread2);
connect(thread2,&QThread::started,object,&MThreadObject::startThread);
connect(this,&Widget::sigSendVal,object,&MThreadObject::slotTest);
thread2->start();
emit sigSendVal(66); //this->sigSendVal(66) 两种方法都可以
结果:
QThreadPool+QRunnable实现:
介绍:由于线程池原理就是将一堆任务分到设置的几个线程中,按照优先级先后执行,所有在存在大批量任务的时候,可以有效的管理线程的开销。QThreadPool c++实现
缺点:使用起来不是很灵活,由于存在任务排队和优先级设置,所有管理较复杂。
适用场景:需要创建大量生命周期短小,且逻辑重复简单的任务。
int activeThreadCount() const //当前的活动线程数量
void clear()//清除所有当前排队但未开始运行的任务
int expiryTimeout() const//线程长时间未使用将会自动退出节约资源,此函数返回等待时间
int maxThreadCount() const//线程池可维护的最大线程数量
void releaseThread()//释放被保留的线程
void reserveThread()//保留线程,此线程将不会占用最大线程数量,从而可能会引起当前活动线程数量大于最大线程数量的情况
void setExpiryTimeout(int expiryTimeout)//设置线程回收的等待时间
void setMaxThreadCount(int maxThreadCount)//设置最大线程数量
void setStackSize(uint stackSize)//此属性包含线程池工作线程的堆栈大小。
uint stackSize() const//堆大小
void start(QRunnable *runnable, int priority = 0)//加入一个运算到队列,注意start不一定立刻启动,只是插入到队列,排到了才会开始运行。需要传入QRunnable ,后续介绍
bool tryStart(QRunnable *runnable)//尝试启动一个
bool tryTake(QRunnable *runnable)//删除队列中的一个QRunnable,若当前QRunnable 未启动则返回成功,正在运行则返回失败
bool waitForDone(int msecs = -1)//等待所有线程运行结束并退出,参数为等待时间-1表示一直等待到最后一个线程退出
void setAutoDelete(bool flag = true)//QRunnable的设置项,用来标识是否在运行结束后自动由线程池释放空间
代码:
.h
#include <QObject>
#include <QRunnable>
class MRunnable : public QObject,public QRunnable
{
Q_OBJECT
public:
MRunnable(int num);
void run();
void setval(int index);
int _index = 0;
int _num = 0;
};
.cpp
#include "mrunnable.h"
#include <QDebug>
#include <QThread>
MRunnable::MRunnable(int num)
{
qDebug()<<"main thread"<<QThread::currentThreadId();
}
void MRunnable::setval(int index)
{
qDebug()<<"---------setval"<<index<<QThread::currentThreadId();
_index = index;
}
void MRunnable::run()
{
qDebug()<<_index<<_num<<"thread 3"<<QThread::currentThreadId();
QThread::msleep(200);
}
调用
QThreadPool pool;
pool.setMaxThreadCount(3);
QList<MRunnable*> runs;
for (int i = 0; i < 5; ++i) {
MRunnable *run = new MRunnable(44);
run->setval(i);
pool.start(run);
}
for (int i = 0; i < runs.size(); ++i) {
delete runs[i];
}
runs.clear();
结果:
QFuture+QtConcurrent实现:
介绍:QFuture + Qt Concurrent是Qt提供的一个并发编程框架,用于简化多线程和并行计算的开发。它提供了一组易于使用的函数和类,可以方便地在多线程环境下处理并发任务。优点简单易用、自动将大的问题拆分成更小的任务,并分配给不同的线程并行执行、异步计算,不会阻塞主线程。(详细介绍1、详细介绍2)
缺点:交互麻烦。
使用场景:需要临时使用一下线程的场景。
代码:
.pro
Qt += concurrent
.h
#include <QWidget>
#include <QDebug>
#include <QFuture>
#include <QtConcurrent>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
public slots:
void slotFinish();
private:
Ui::Widget *ui;
QFuture<int> m_future;
QFutureWatcher<int> m_watcher;
};
.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
auto func([&](int val){
val = 2*val;
qDebug()<<"thread 4"<<val<<QThread::currentThreadId();
return val;
});
//异步调用
QObject::connect(&m_watcher, &QFutureWatcher<void>::finished, this, &Widget::slotFinish);
int val = 123;
m_future = QtConcurrent::run(func,val);
m_watcher.setFuture(m_future);
// future.waitForFinished();//同步调用
qDebug()<<"main thread"<<QThread::currentThreadId()<<m_future.result();
}
Widget::~Widget()
{
delete ui;
}
void Widget::slotFinish()
{
int res = m_future.result();
qDebug()<<"watcher finish"<<res<<QThread::currentThreadId();
}
结果:
std::thread实现:
介绍:直接调用,优点使用方便灵活。缺点:无法完成复杂的交互。
适用场景:适用需要临时创建线程的场景下。
代码:
#include <thread>
void test()
{
std::thread thread5([&](){
qDebug()<<"thread 5"<<QThread::currentThreadId();
});
thread5.detach();
qDebug()<<"main thread"<<QThread::currentThreadId();```
}
结果: