Qt多线程有两两种方式,第一种继承QThread,复写run()函数,但是run()和main()类似,run()函数才是子线程的入口函数,所以在设计到类的操作时,必须把对象或者指针放在run函数里面,否则就不在一个线程里面了,会出现错误。
第二种方式,继承QObject,通过moveToThread()将自定义的线程添加到子线程QThread里,然后信号槽的方式实现,shix实现主线程和子线程的交互。
本文只为给自己学习QT多线程做个笔记。本文使用第二种方式,Qt官方主推的方式。
注意:
继承QObject,调用moveToThread方法用的时候要强调的几个重点:
自定义的MyThread线程类的对象在创建时不能指定父对象!
启动子线程后,并没有启动子线程处理函数;
启动子线程处理函数必须用signal-slot方式!!!
在线程处理函数内部,绝对不允许操作ui图形界面(比如跳个弹窗等等),线程内部通常是纯数据处理!
线程退出:
线程在使用时,需要判断线程的状态。isRunning()。
thread->quit();//退出线程,会等待线程执行完毕。
thread->wait();//回收资源
子线程是while(1)一般使用设置标志位来实现线程的退出。
myThread->setFlag(true);
代码如下:
1.pro文件
#-------------------------------------------------
#
# Project created by QtCreator 2019-10-29T14:52:07
#
#-------------------------------------------------QT += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsTARGET = ThreadUI2
TEMPLATE = app# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0CONFIG += c++11SOURCES += \main.cpp \widget.cpp \mythread.cppHEADERS += \widget.h \mythread.hFORMS += \widget.ui# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
2.mythread.h文件
#ifndef MYTHREAD_H
#define MYTHREAD_H#include <QObject>class MyThread : public QObject
{Q_OBJECT
public:explicit MyThread(QObject *parent = nullptr);~MyThread();//线程处理函数void MyTimeout();void setFlag(bool flag = true);signals:void mySignal();//定义一个信号,在该子线程中每秒发射一次该信号private:bool isStop;
public slots:
};#endif // MYTHREAD_H
3.mythread.h文件
#include "mythread.h"
#include<QThread>
#include<QtDebug>
MyThread::MyThread(QObject *parent) : QObject(parent)
{isStop=false;
}MyThread::~MyThread()
{}void MyThread::MyTimeout()
{while(isStop==false){QThread::sleep(1);emit mySignal();qDebug()<<"sub thread :"<<QThread::currentThread();if(true==isStop){break;}}
}void MyThread::setFlag(bool flag)
{isStop=flag;
}
4.widget.h文件
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include"mythread.h"
#include<QThread>namespace Ui {
class Widget;
}class Widget : public QWidget
{Q_OBJECTpublic:explicit Widget(QWidget *parent = nullptr);~Widget();signals:void startThread();//启动子线程的信号private slots:void on_pushButtonStart_clicked();void on_pushButtonStop_clicked();void dealSignal();void dealClose();private:Ui::Widget *ui;MyThread *myT;QThread *thread;
};#endif // WIDGET_H
5.widget.cpp文件
#include "widget.h"
#include "ui_widget.h"
#include<QtDebug>
Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);myT=new MyThread;//不能指定父对象thread=new QThread(this);//创建子线程myT->moveToThread(thread);//把自定义的线程加入到子线程中connect(myT,&MyThread::mySignal,this,&Widget::dealSignal);qDebug()<<"main thread: "<<QThread::currentThread();connect(this,&Widget::startThread,myT,&MyThread::MyTimeout);connect(this,&Widget::destroyed,this,&Widget::dealClose);//右上角X 关了 窗口线程还在运行}Widget::~Widget()
{delete ui;
}void Widget::dealSignal()
{static int i=0;i++;ui->lcdNumber->display(i);
}void Widget::dealClose()
{on_pushButtonStop_clicked();//停止线程delete myT; //释放线程空间
}
//start按钮
void Widget::on_pushButtonStart_clicked()
{if(thread->isRunning()==true){return;}//启动线程 但是满意启动线程处理函数thread->start();myT->setFlag(false);//不能直接调用线程处理函数,直接调用导致线程处理函数和主线程在同一个线程// myT->myTimeout();///只能通过signal - slot方式emit startThread();}//stop按钮
void Widget::on_pushButtonStop_clicked()
{if(thread->isRunning()==false){return;}myT->setFlag(true);thread->quit();thread->wait();}
6.widget.ui文件
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>Widget</class><widget class="QWidget" name="Widget"><property name="geometry"><rect><x>0</x><y>0</y><width>418</width><height>276</height></rect></property><property name="windowTitle"><string>Widget</string></property><layout class="QVBoxLayout" name="verticalLayout" stretch="2,0"><item><widget class="QLCDNumber" name="lcdNumber"/></item><item><layout class="QHBoxLayout" name="horizontalLayout"><item><widget class="QPushButton" name="pushButtonStart"><property name="text"><string>Start</string></property></widget></item><item><widget class="QPushButton" name="pushButtonStop"><property name="text"><string>Stop</string></property></widget></item></layout></item></layout></widget><layoutdefault spacing="6" margin="11"/><resources/><connections/>
</ui>
7.UI界面