在Qt 中QThread 类提供了于平台无关的线程,一个QThread代表一个在应用程序中可以独立控制的线程,可以和进程中的其他线程分享数据。
QThread 对象管理程序中的一个控制线程。QThreads 在 run() 中开始执行。默认情况下,run() 通过调用 exec() 来启动事件循环,并在线程内运行 Qt 事件循环。
QThread中的函数:
exec() | 进入事件循环并等待 exit() 被调用,返回传递给exit() 的值。如果通过 quit() 调用 exit(),则返回的值为 0。 此函数旨在从 run() 中调用。必须调用此函数才能启动事件处理 |
exit() | 告知线程的事件循环以返回代码退出 |
currentThread() | 返回指向管理当前正在执行的线程的 QThread 的指针。 |
idealThreadCount() | 返回可在系统上运行的理想线程数,如果无法检测到处理器内核数,则此函数返回 1。 |
isDone() | 如果线程完成返回true 否则返回 false |
isRunning() | 如果线程正在运行返回true 否则返回 false |
loopLevel() | 返回线程的当前事件循环级别 |
msleep() | 强制当前线程休眠毫秒 |
sleep() | 强制当前线程休眠几秒钟,此功能不保证准确性。在重负载条件下,应用程序可能会休眠超过秒。 |
usleep() | 强制当前线程休眠 usecs微秒,此功能不保证准确性。在重负载条件下,应用程序可能比 usecs 休眠时间更长 |
priority() | 返回正在运行的线程的优先级 |
isInterruptionRequest() | 如果应停止在此线程上运行的任务返回true否则返回false |
requestInterruption() | 请求中断线程。该请求是建议性的,由线程上运行的代码决定是否以及如何对此类请求进行操作。此函数不会停止线程上运行的任何事件循环,也不会以任何方式终止它。 |
run() | 线程的起点,调用 start() 后,新创建的线程调用此函数,您可以重新实现此函数以促进高级线程管理 |
wait() | 阻塞线程,直到如果线程已完成,此函数将返回 true。如果线程尚未启动,它也返回 true。或到了最后期限。如果达到截止时间,此函数将返回 false |
setEventDispatcher() | 设置线程的事件调度 |
setPriority() | 设置线程优先级 |
setStackSize() | 设置线程的最大堆栈大小 |
stackSize() | 返回线程的最大堆栈大小 |
yieldCurrentThread() | 将当前线程的执行生成到另一个可运行的线程 |
信号:
finished() | 此信号在完成执行之前从关联的线程发出 |
started() | 在调用run() 函数之前,当关联线程开始执行时,此信号从关联线程发出。 |
槽函数:
quit() | 告知线程的事件循环退出并返回代码 0(成功)。等效于调用 QThread::exit(0) |
start() | 通过调用 run() 开始执行线程。操作系统将根据优先级参数调度线程。如果线程已在运行,则此函数不执行任何操作 |
terminate() | 终止线程的执行。线程可能会也可能不会立即终止,具体取决于操作系统的调度策略。在 terminate() 之后使用 QThread::wait() 可以肯定。 |
创建一个单独的线程:
创建一个QThread的子类,然后重新实现run()函数,QThread是从run()函数开始执行,在run()函数中需要调用exec()来开启事件循环。
class widget::public QThread
{
protected:
void run()override;
}
void widget::run()//重写run函数
{
QTcpSocket socket;
socket.connectToHost(hostName,portNumber);
exec();//开启事件循环
}
在线程中创建一个QTcpSocket,然后执行这个线程的事件循环。
注意:线程中无法使用任何界面部件类
线程中函数的使用:
start()开启线程,start会自动调用run()函数
线程开始、结束、终止会发出 started()、finished()和terminated()
可以使用isFinnished()和isRuning()查询状态,使用wait()来阻塞,直到线程结束执行,每个线程都会从操作系统中获取自己的堆栈,使用setStackSize()可以设置一个自定义的堆栈。
每个线程都可以有自己的事件循环,可以通过调用exec()函数来启动事件循环,可以调用exit()或quit()来停止事件循环 ,
线程中拥有一个事件循环,使得它可以关联其他线程中的信号到本线程的槽上,这使用了队列关联机制,使用connect关联时将Qt::connectionType类型参数指定Qt::QueuedConection
拥有事件循环就可以使用一些需要事件循环的类
使用terminate()函数,可以强制终止一个正在执行的线程,线程是否会立即停止也会受操作系统的调度策略影响,可以在调用完terminate()后调用QThread::wiat()来同步终止,一般来说不会推荐使用该函数,可能会因线程的任意停止而无法进行一些清理操作。
sleep()休眠 n秒、 msleep()休眠n毫秒 、usleep()暂停n微妙
currentThread()和currentThread()可以返回当前执行线程的表示符,前者返沪一个该线程的系统特定的ID;后者返回一个QThread指针
举一个例子:
点击开启线程按钮,开启线程,点击暂停,线程暂停,且在QLineEdit上显示数据
创建一个thread类:
thread.h
#ifndef THREAD_H
#define THREAD_H
#include <QObject>
#include<QThread>
class Thread : public QThread
{
Q_OBJECT
public:
explicit Thread(QObject *parent = nullptr);
void stop();//暂停
protected:
void run() override;
int i=0;//记录数据
volatile bool stoped;//存放暂停的条件,使用volatile 使得该值可以获取最新值
signals:
};
#endif // THREAD_H
thread.cpp
#include "thread.h"
#include<QWidget>
#include<QDebug>
Thread::Thread(QObject *parent) : QThread(parent)
{
stoped=true;
}
void Thread::run()
{
while(stoped)
{
qDebug()<<QString("数字为:%1").arg(i);
msleep(1000);//暂停一秒
i++;
}
stoped=true;
}
void Thread::stop()
{
stoped=false;
}
主窗口:widget
ui界面中添加以下空间并转到槽
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "thread.h"
#include<QDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
private:
Ui::Widget *ui;
Thread th;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()//开启线程
{
th.start();//开启线程
qDebug()<<"线程已开启";
ui->pushButton->setEnabled(false);
ui->pushButton_2->setEnabled(true);
}
void Widget::on_pushButton_2_clicked()//暂停
{
if(th.isRunning())
{
th.stop();//暂停
qDebug()<<"线程已暂停";
ui->pushButton->setEnabled(true);
ui->pushButton_2->setEnabled(false);
}
}
运行效果:
点击开启
点击暂停:
使用QObject::moveToThread()函数来创建线程,将工作器对象移动到线程来使用工作器对象。
参考文献:
Q阅读类|Qt核心 5.15.12