1.QThread线程基础
QThread是Qt线程中有一个公共的抽象类,所有的线程类都是从QThread抽象类中派生的,需要实现QThread中的虚函数run(),通过start()函数来调用run函数。
void run()函数是线程体函数,用于定义线程的功能。
void start()函数是启动函数,用于将线程入口地址设置为run函数。
void terminate()函数用于强制结束线程,不保证数据完整性和资源释放。
QCoreApplication::exec()总是在主线程(执行main()的线程)中被调用,不能从一个QThread中调用。在GUI程序中,主线程也称为GUI线程,是唯一允许执行GUI相关操作的线程。另外,必须在创建一个QThread前创建QApplication(or QCoreApplication)对象。
当线程启动和结束时,QThread会发送信号started()和finished(),可以使用isFinished()和isRunning()来查询线程的状态。
从Qt4.8起,可以释放运行刚刚结束的线程对象,通过连接finished()信号到QObject::deleteLater()槽。
使用wait()来阻塞调用的线程,直到其它线程执行完毕(或者直到指定的时间过去)。
静态函数currentThreadId()和currentThread()返回标识当前正在执行的线程。前者返回线程的ID,后者返回一个线程指针。
要设置线程的名称,可以在启动线程之前调用setObjectName()。如果不调用setObjectName(),线程的名称将是线程对象的运行时类型(QThread子类的类名)。
应用程序的线程称为主线程,额外创建的线程为工作线程。一般在主线程里面创建工作线程,并调用 start() 开始执行工作线程的任务。start()会在内部调用run()函数,进入工作线程的循环,在 run() 函数里调用 exit() 或 quit() 可以结束线程的事件循环,或在主线程里调用 terminate() 强制结束线程。
QThread类的主要接口 | ||
---|---|---|
类型 | 函数 | 功能 |
公共函数 | 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 quit() | 退出线程的事件循环,并返回代码0,等效于exit() |
void start(Priority priority) | 内部调用run()函数开始执行线程,操作系统根据priority参数进行调度终止线程的运行,但不是立即结束线程,而是等待操作系统结束线程。使用terminate()之后应使用wait() | |
void terminate() | ||
信号 | void finished() | 在线程结束时发射此信号 |
void start() | 在线程开始执行、run()函数被调用之前发射此信号 | |
静态公共函数 | int idealThreadCount() | 返回系统上能运行的线程的理性个数 |
void msleep(unsigned long msecs) | 强制当前线程休眠msecs毫秒 | |
void sleep(unsigned long secs) | 强制当前线程休眠secs秒 | |
void usleep(unsigned long usecs) | 强制当前线程休眠uecs微秒 | |
保护函数 | virtual void run() | start()调用run()函数开始线程任务的执行,所以在run()函数里实现线程的任务功能 |
int exec() | 由run()函数调用,进入线程的时间循环,等待exit()退出 |
2.小案例
threaddlg.h
#ifndef THREADDLG_H
#define THREADDLG_H
#define MAXSIZE 5
#include "workthread.h"
#include <QDialog>
#include <QPushButton>
QT_BEGIN_NAMESPACE
namespace Ui { class Threaddlg; }
QT_END_NAMESPACE
class Threaddlg : public QDialog
{
Q_OBJECT
public:
Threaddlg(QWidget *parent = nullptr);
~Threaddlg();
private:
Ui::Threaddlg *ui;
QPushButton *startBtn;
QPushButton *stopBtn;
QPushButton *quitBtn;
WorkThread *workThread[MAXSIZE];
public slots:
void slotStart();
void slotStop();
};
#endif // THREADDLG_H
threaddlg.cpp
#include "threaddlg.h"
#include "ui_threaddlg.h"
#include<QHBoxLayout>
Threaddlg::Threaddlg(QWidget *parent)
: QDialog(parent)
, ui(new Ui::Threaddlg)
{
ui->setupUi(this);
setWindowTitle(QStringLiteral("线程"));
startBtn=new QPushButton(QStringLiteral("线程"));
stopBtn=new QPushButton(QStringLiteral("停止"));
quitBtn=new QPushButton(QStringLiteral("退出"));
QHBoxLayout *mainLayout=new QHBoxLayout(this);
mainLayout->addWidget(startBtn);
mainLayout->addWidget(stopBtn);
mainLayout->addWidget(quitBtn);
connect(startBtn,SIGNAL(clicked()),this,SLOT(slotStart()));
connect(stopBtn,SIGNAL(clicked()),this,SLOT(slotStop()));
connect(quitBtn,SIGNAL(clicked()),this,SLOT(close()));
}
Threaddlg::~Threaddlg()
{
delete ui;
}
void Threaddlg::slotStart()
{
for(int i=0;i<MAXSIZE;i++){
workThread[i]=new WorkThread; //创建指定数目的WorkThread线程,并将其保存在指针数组workThread中
}
for(int i=0;i<MAXSIZE;i++){
workThread[i]->start();//调用QThread基类start函数,此函数将启动run,使线程开始真正运行
}
startBtn->setEnabled(false);
stopBtn->setEnabled(true);
}
void Threaddlg::slotStop()
{
for(int i=0;i<MAXSIZE;i++){
workThread[i]->terminate();//terminate函数不会立刻终止这个线程,该线程何时终止取决于操作系统的调度策略
workThread[i]->wait();//使线程阻塞等待直到退出或超时
}
startBtn->setEnabled(true);
stopBtn->setEnabled(false);
}
WorkThread.h
#ifndef WORKTHREAD_H
#define WORKTHREAD_H
#include <QThread>
#include <QtDebug>
class WorkThread : public QThread
{
public:
WorkThread();
protected:
void run();
};
#endif // WORKTHREAD_H
WorkThread.cpp
#include "workthread.h"
WorkThread::WorkThread()
{
}
void WorkThread::run()
{
while(true)
{
for(int n=0;n<10;n++)
qDebug()<<n<<n<<n<<n<<n<<n<<n;
}
}
结果:
1个线程 5个线程
可以看出,一个线程输出是顺序打印的,5个线程也就是多线程的输出结果是乱码打印的
犯了一个很低级的错误
报错为:
原来是因为: 对了,就是clicked没有加括号
2.案例2
多线程(这里是2个)并发操作,分别负责打印基数和偶数
ui设计器设计控件如下:
my_thread.h
#ifndef MY_THREAD_H
#define MY_THREAD_H
#include <QObject>
#include <QThread>
class my_thread : public QThread //线程一
{
Q_OBJECT
public:
my_thread() {stopped=false;}
void stop();
protected:
void run();
private:
bool stopped;
};
class my_thread_2 : public QThread //线程二
{
Q_OBJECT
public:
my_thread_2() {stopped=false;}
void stop();
protected:
void run();
private:
bool stopped;
};
#endif // MY_THREAD_H
my_thread.cpp
#include "my_thread.h"
#include<QDebug>
void my_thread::run()
{
int i=0;
while(!stopped)
{
qDebug()<<"MyThread:"<<i;
msleep(1000);//线程休眠1s
i+=2;
}
stopped=false;
}
void my_thread::stop()
{
stopped=true;
}
void my_thread_2::run()
{
int i=1;
while(!stopped)
{
qDebug()<<"MyThread:"<<i;
msleep(1000);//线程休眠1s
i+=2;
}
stopped=false;
}
void my_thread_2::stop()
{
stopped=true;
}
widght.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <my_thread.h>
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();
void on_pushButton_3_clicked();
void on_pushButton_4_clicked();
private:
Ui::Widget *ui;
my_thread thread;
my_thread_2 thread2;
};
#endif // WIDGET_H
widght.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()
{
thread.start();
ui->pushButton->setEnabled(false);
ui->pushButton_2->setEnabled(true);
}
void Widget::on_pushButton_2_clicked()
{
if(thread.isRunning())
{
thread.stop();
}
ui->pushButton->setEnabled(true);
ui->pushButton_2->setEnabled(false);
}
void Widget::on_pushButton_3_clicked()
{
thread2.start();
ui->pushButton_3->setEnabled(false);
ui->pushButton_4->setEnabled(true);
}
void Widget::on_pushButton_4_clicked()
{
if(thread2.isRunning())
{
thread2.stop();
}
ui->pushButton_3->setEnabled(true);
ui->pushButton_4->setEnabled(false);
}
结果:首先点击启动线程一,再点击线程二,然后点击结果线程一,在结束线程二(顺序随便)这里我操作后的结果为:文章来源:https://www.toymoban.com/news/detail-698127.html
文章来源地址https://www.toymoban.com/news/detail-698127.html
到了这里,关于QT 初识多线程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!