Qt开发——多线程基础知识学习

Qt4和Qt5的多线程使用方法有些许差异,Qt5的线程使用方式更加灵活。

首先初始化一个Qt Application Widget,并添加一个类命名为mythread,基类为Qobject。

mythread类具体实现如下:

class MyThread : public QObject
{
    Q_OBJECT

public:
    explicit MyThread(QObject *parent = nullptr);

    //线程处理函数
    void myTimeout();

    void setFlag(bool flag = true);


signals:
    void mySignal();

private:
    bool isStop;

};
#include "mythread.h"
#include <QThread>

#include <QMessageBox>

//宏定义打印调试
#include<QtDebug>
#define cout qDebug() <<"["<<__FILE__<<":"<<__LINE__<<"]"

MyThread::MyThread(QObject *parent) : QObject(parent)
{
    isStop =false;
}

void MyThread::myTimeout()
{
    while(isStop == false)
    {
        //线程运行函数不可以操作图形界面,编译可通过,运行会报错
        //QMessageBox::aboutQt(NULL);

        QThread::sleep(1);
        emit mySignal();
        cout<<"子线程号:"<<QThread::currentThread();

//        if(true == isStop)
//        {
//            break;
//        }
    }

}

void MyThread::setFlag(bool flag)
{
    isStop = flag;
}

widget类的实现代码如下:

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    void dealSignal();      //信号处理
    void dealClose();       //关闭窗口处理

signals:
    void startThread();     //开启线程

private slots:
    void on_pushButton_clicked();   //按钮start

    void on_pushButton_2_clicked(); //按钮stop

private:
    Ui::Widget *ui;
    MyThread *myT;
    QThread *thread;
};
#include "widget.h"
#include "ui_widget.h"

//宏定义打印调试
#include<QtDebug>
#define cout qDebug() <<"["<<__FILE__<<":"<<__LINE__<<"]"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //指定父对象,会导致自定义线程无法加入到子线程中
    //myT = new MyThread(this);

    //动态分配空间,不能指定父对象
    myT =new MyThread;

    //创建子线程
    thread = new QThread(this);

    //自定义线程加入到子线程中
    myT->moveToThread(thread);

    connect(myT, &MyThread::mySignal, this, &Widget::dealSignal);
    cout<<"connect1";

    cout<<"主线程号:"<<QThread::currentThread();

    connect(this, &Widget::startThread, myT, &MyThread::myTimeout);
    cout<<"connect2";

    connect(this, &Widget::destroyed, this, &Widget::dealClose);
    cout<<"connect3";

    //connect函数第五个参数的作用
    //多线程时才有意义,指定连接方式,共有三种,Qt::ConnectionType
    //默认的时候,如果是多线程,默认使用队列,如果是单线程,默认使用直接方式
    //队列:槽函数所在线程和接受者一样
    //直接:槽函数所在线程和发送者一样
}

Widget::~Widget()
{
    delete ui;
}

void Widget::dealClose()
{
  on_pushButton_2_clicked();
  delete myT;
  cout<<"关闭窗口,回收线程";
}


void Widget::on_pushButton_clicked()
{
    if(thread->isRunning() == true)
    {
        cout<<"线程已经处于启动状态";
        return;
    }

    //启动线程,没有启动线程处理函数
    thread->start();
    myT->setFlag(false);

    //不能直接调用线程处理函数,直接调用导致线程处理函数和主线程是在同一个线程
    //myT->myTimeout();

    //只能通过信号和槽的方式调用
    emit startThread();

}

void Widget::dealSignal()
{
    static int i = 0;
    i++;
    ui->lcdNumber->display(i);
}

void Widget::on_pushButton_2_clicked()
{
    if(thread->isRunning() == false)
    {
        cout<<"线程已经处于关闭状态";
        return;
    }

    cout<<"stop,回收线程";
    myT->setFlag(true);
    thread->quit();
    thread->wait();
}

UI界面如下:

widget默认为主线程,从主线程创建一个mythread和一个QThread,通过movetothread()函数将子线程myT放入thread中运行。通过isStop标志位控制子线程的开启和关闭。子线程通过while循环控制LCD显示数字累加。

注意事项:

1.子线程的开启必须通过信号与槽的机制运行,不能直接调用线程处理函数,直接调用导致线程处理函数和主线程是在同一个线程;

2.初始化myThread时不能指定父对象(this),否则报错;

3.线程运行函数不可以操作图形界面,编译可通过,运行会报错;

4.connect()函数有第五个参数,第五个参数在多线程情况下使用,用于指定线程连接方式Qt::ConnectionType;

5.运行结束后,要考虑线程和类的回收( thread->quit(); thread->wait();),要考虑stop和关闭窗口两种情况,stop按钮通过槽函数实现;关闭窗口通过Widget::destroyed信号触发槽函数实现;

6.通过thread->isRunning(),判断线程运行状态,避免start和stop出现冗余操作。

视频教程参考(p78-p80):QT开发全套视频_哔哩哔哩_bilibili

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值