QT增加线程函数步骤流程

在使用线程的时候,不仅要关注线程开启的时机,同时还要关注线程安全退出,这样才能保证程序的健壮性,如果线程开启的较多,且开启关闭比较频繁,建议使用线程池来处理。开启线程有三种方式:

第一种:继承自QThread,然后重写run函数,把要处理的事项放在run函数中。

第二种:继承自QObject的类。

第三种:C++的开线程方式;

一,继承QThread的子线程

继承QThread是创建线程的一个普通方法。其中创建的线程只有run()方法在线程里的。

1,新建一个C++类,并继承自QThread

2,输入线程类的名称,并勾选图中所示内容,点击下一步,点击完成即可

 3,在添加的线程类中,.h文件中添加run函数,用于重写

4,在线程类的cpp文件中,在run()中添加要处理的逻辑业务

5,子线程只能处理数据,不能直接在子线程操作界面(否则会崩溃),如果想要操作界面,需要将子线程的数据传递给界面主线程进行操作,这样就用到了我们信号和槽,子线程和主线程之间传递参数。子线程和主线程之间传递数据: 

(1)首先,在主界面的头文件中,添加线程对象:

#include"usbthread.h"和usbThread myusbThread;

(2) 在主界面的cpp文件中,添加信号和槽连接(这里用到自定义信号),在子线程的头文件中定义你要传递的数据,这里使用的自定义结构体信号stru_usb_data,参数是结构体形式。

signals:void send_usbFlagSignal(stru_usb_data usb_data);

(3) 在界面主线程中的构造函数中开启线程,也可以根据自己的需要开启线程(比如,点击按钮时开启,或者接收到信号触发时开启,这个根据用户自己的需求来定);并且 在子线程的cpp文件中通过emit函数发送该信号

(4)  在子线程的cpp文件中通过emit函数发送该信号

(5) 在主界面cpp文件中连接信号和槽,用于接收子线程传递过来的数据,这里的信号是自定义的信号,参数是非基本类型,所以需要对信号进行注册。于是就实现了一个界面主线程,一个数据处理线程,子线程提供数据,通过信号和槽传递给界面主线程,界面主线程对接收到的数据进行处理。

6,线程运行完毕,需要安全退出(线程异常退出有可能导致崩溃),这里安全退出有两种方式,一种是标志位,一种是通过检查线程运行状态,通过quit,wait来实现,这里我们用第二种方式退出线程。

二,继承QObject的线程

自定义一个继承自QObject的类,把要处理的事情放在这个类中实现,然后再new一个QThread指定,它通过QObject::moveToThread()方法(把这个类通过moveToThread移动到指定的线程中进行处理),将一个QObeject的类转移到一个线程里执行。

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QThread>
#include <QDebug>
#include <QPushButton>
#include <QMutexLocker>
#include <QMutex>

/* 工人类 */
class Worker;
class MainWindow : public QMainWindow
{
    Q_OBJECT

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

private:
    /* 开始线程按钮 */
    QPushButton *pushButton1;

    /* 打断线程按钮 */
    QPushButton *pushButton2;

    /* 全局线程 */
    QThread workerThread;

    /* 工人类 */
    Worker *worker;

private slots:
    /* 按钮1点击开启线程 */
    void pushButton1Clicked();

    /* 按钮2点击打断线程 */
    void pushButton2Clicked();

    /* 用于接收工人是否在工作的信号 */
    void handleResults(const QString &);

signals:
    /* 工人开始工作(做些耗时的操作 ) */
    void startWork(const QString &);
};




/* Worker类,这个类声明了doWork1函数,将整个Worker类移至线程workerThread */
class Worker : public QObject
{
    Q_OBJECT

private:
    /* 互斥锁 */
    QMutex lock;
    /* 标志位 */
    bool isCanRun;
public slots:
    /* 耗时的工作都放在槽函数下,工人可以有多份不同的工作,但是每次只能去做一份 */
    void doWork1(const QString &parameter) {

        /* 标志位为真 */
        isCanRun = true;
        /* 死循环 */
        while (1) 
        {
            /* 此{}作用是QMutexLocker与lock的作用范围,获取锁后,运行完成后即解锁 */
              {
                QMutexLocker locker(&lock);
                /* 如果标志位不为真 */
                if (!isCanRun) 
                {
                    /* 跳出循环 */
                    break;
                }
            }
            /* 使用QThread里的延时函数,当作一个普通延时 */
            QThread::sleep(2);
            emit resultReady(parameter + "doWork1函数");
        }
        /* doWork1运行完成,发送信号 */
        emit resultReady("打断doWork1函数");
    }

    // void doWork2();...

public:
    /* 打断线程(注意此方法不能放在槽函数下) */
    void stopWork() 
    {
        qDebug()<<"打断线程"<<endl;
        /* 获取锁后,运行完成后即解锁 */
        QMutexLocker locker(&lock);
        isCanRun = false;
    }

signals:
    /* 工人工作函数状态的信号 */
    void resultReady(const QString &result);
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    /* 设置显示位置与大小 */
    this->setGeometry(0, 0, 800, 480);
    pushButton1 =  new QPushButton(this);
    pushButton2 =  new QPushButton(this);


    /* 设置按钮的位置大小 */
    pushButton1->setGeometry(300, 200, 80, 40);
    pushButton2->setGeometry(400, 200, 80, 40);

    /* 设置两个按钮的文本 */
    pushButton1->setText("开启线程");
    pushButton2->setText("打断线程");

    /* 工人类实例化 */
    worker = new Worker;

    /* 将worker类移至线程workerThread */
    worker->moveToThread(&workerThread);

    /* 信号槽连接 */

    /* 线程完成销毁对象 */
    connect(&workerThread, SIGNAL(finished()),worker, SLOT(deleteLater()));
    connect(&workerThread, SIGNAL(finished()),&workerThread, SLOT(deleteLater()));

    /* 发送开始工作的信号,开始工作 */
    connect(this, SIGNAL(startWork(QString)),worker, SLOT(doWork1(QString)));

    /* 接收到worker发送过来的信号 */
    connect(worker, SIGNAL(resultReady(QString)), this, SLOT(handleResults(QString)));

    /* 点击按钮开始线程 */
    connect(pushButton1, SIGNAL(clicked()),this, SLOT(pushButton1Clicked()));

    /* 点击按钮打断线程 */
    connect(pushButton2, SIGNAL(clicked()),this, SLOT(pushButton2Clicked()));
}

MainWindow::~MainWindow()
{
    /* 打断线程再退出 */
    worker->stopWork();
    workerThread.quit();
    /* 阻塞线程2000ms,判断线程是否结束 */
    if (workerThread.wait(2000)) 
    {
        qDebug()<<"线程结束"<<endl;
    }
}

void MainWindow::pushButton1Clicked()
{
    /* 字符串常量 */
    const QString str = "正在运行";
    /* 判断线程是否在运行 */
    if(!workerThread.isRunning()) 
    {
        /* 开启线程 */
        workerThread.start();
    }
    /* 发送正在运行的信号,线程收到信号后执行后返回线程耗时函数 + 此字符串 */
    emit this->startWork(str);
}

void MainWindow::pushButton2Clicked()
{
    /* 如果线程在运行 */
    if(workerThread.isRunning()) 
    {
        /* 停止耗时工作,跳出耗时工作的循环 */
        worker->stopWork();
    }
}

void MainWindow::handleResults(const QString & results)
{
    /* 打印线程的状态 */
    qDebug()<<"线程的状态:"<<results<<endl;
}

  • 22
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寒听雪落

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值