一.Qt中使用多线程的几种方法
1.继承 QThread ,重载 run 函数
2. 继承 QObject ,使用 moveToThread 将 QObject 对象移动到另一个线程中
3. 继承 QRunnable,使用 QThreadPool
4. 直接使用 QtConcurrent::run 写入函数和参数,自动管理线程的创建和销毁
二.实验分析
1.继承 QThread
一个 QThread 类的对象管理一个线程。通过继承 QThread 类定义线程类,并重定义 QThread 的虚函数 run(),在函数 run() 里处理线程的事件循环。
使用 start 启动线程,run() 方法一般是一个无限循环,在 run() 方法中使用 quit() 或 exit() 退出事件循环;
实验思路:编写一个多线程打印自增数字和时间以及线程id
线程类:
#include <QThread>
#include <QDebug>
#include <QDateTime>
class filetrans : public QThread
{
Q_OBJECT
public:
filetrans();
void setCount(double x)//设置初始值
{
count=x;
}
void setState(bool state_)//设置打印状态
{
state=state_;
}
void run() override
{
while(state)//判断是否打印
{
QDateTime times=QDateTime::currentDateTime();
QString timestr=times.toString("hhmmsszzz");
qDebug()<<"当前时间:"<<timestr<<"-------------------"<<count++<<
" Thread ID: " << QThread::currentThreadId();
msleep(100);
}
}
private:
double count;
bool state=false;
};
直接在主函数中进行管理:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
create(5);//创建多线程
for(auto thread:thread_list)
{
thread->setCount(2);
thread->setState(true);//开启打印
thread->start();//启动线程
}
QThread::sleep(3);
for(auto thread:thread_list)
{
thread->setState(false);//关闭打印
}
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::create(int count)
{
for(int i=0;i<count;i++)//创建线程数组
{
filetrans *filetran=new filetrans();
thread_list.push_back(filetran);
}
}
打印结果:
结果分析:
1.通过线程 id 看出有 5 个线程,和预想结果一致
2.通过每一个打印的时间看出线程的运行是异步的
拓展:同步和异步
同步(阻塞):线程按照严格的顺序依次执行,一个线程可能需要等待另一个线程完成后才能继续执行。这种方式可以保证线程之间的数据一致性,但可能会导致程序的响应速度变慢,特别是当某些线程需要等待耗时操作完成时。
异步(非阻塞):线程可以并行执行,不需要等待其他线程完成。每个线程都可以独立执行,无需等待其他线程的结果。这种方式可以提高程序的响应速度和性能,但也需要额外考虑线程安全和数据一致性的问题。
举例分析:我要吃饭说话玩手机
同步(阻塞):只能先吃饭,再说话,接着玩手机
异步(非阻塞):边吃饭,边说话,边玩手机
2. 继承 QObject ,使用 moveToThread
实验思路:在主线程和子线程中同时打印时间
继承类:
#include <QObject>
#include <QDateTime>
#include <QThread>
#include <QDebug>
class movethread : public QObject
{
Q_OBJECT
public:
explicit movethread(QObject *parent = nullptr);
void displayTime()
{
QDateTime times=QDateTime::currentDateTime();
QString timestr=times.toString("hhmmsszzz");
qDebug()<<timestr;
}
void run()
{
for(int i=0;i<5;i++)
{
displayTime();
QThread::sleep(1);
}
}
};
主线程:
void displayTime()
{
QDateTime times=QDateTime::currentDateTime();
QString timestr=times.toString("hhmmsszzz");
qDebug()<<"_______________________主线程"<<timestr;
}
void displayall()
{
for(int i=0;i<5;i++)
{
displayTime();
QThread::sleep(1);//每次休眠1秒
}
}
QThread thread1;//创建子线程
movethread move1;//创建继承类对象
//将子线程的启动和继承类对象的run函数相连接
QObject::connect(&thread1, &QThread::started, &move1, &movethread::run);
//将类对象放到子线程中
move1.moveToThread(&thread1);
thread1.start();//启动子线程
displayall();//主线程打印开始
thread1.wait();//阻塞主线程等待子线程完成,避免主线程先结束
打印结果:
结果分析:
1.两个线程并行运行,符合预想