Qt实现多线程编程的两种方式

Qt实现多线程编程的两种方式


方式一: 继承自QThread类,覆写run函数。此实现方法只有run函数内的代码是运行在子线程内。

代码示例:

#ifndef QDEMOTHREAD_H
#define QDEMOTHREAD_H

#include <QThread>
#include <QDebug>

class QDemoThread : public QThread
{
    Q_OBJECT

public:
    QDemoThread(QObject* parent = nullptr);
    ~QDemoThread();

protected:
    void run() override;

public:
    void stop();

private:
    bool flag;
};

#endif // QDEMOTHREAD_H

#include "qdemothread.h"

QDemoThread::QDemoThread(QObject* parent) : QThread(parent)
{

}

QDemoThread::~QDemoThread()
{

}

void QDemoThread::run()
{
    flag = true;
    while(flag)
    {
        qDebug() << "thread id:" << QThread::currentThreadId();
        sleep(1);
    }
}

void QDemoThread::stop()
{
    flag = false;
    if(isRunning())
    {
        exit();  // 结束线程
        wait();  // 等待退出
    }
}


#include "widget.h"
#include "ui_widget.h"

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

    demoThread = new QDemoThread(this);

    qDebug() << "main thread id:" << QThread::currentThreadId();
}

Widget::~Widget()
{
    demoThread->stop();  // 退出线程
    delete ui;
}

void Widget::on_pushButton_clicked()
{
    if(!demoThread->isRunning())
    {
        demoThread->start();  // 启动线程
    }
}

运行效果:
在这里插入图片描述


方式二: 创建一个QThread和QWorker(继承自QObject)类对象,使用moveToThread函数移动到thread中运行,通过thread类start信号和worker的init槽函数绑定,init槽函数内是一些初始化操作,然后定义个定时器,周期触发doWork()。

网上有很多教程是在doWork()中使用while(isRunning)死循环的形式,不建议这么干,如果线程一直在doWork中死循环,那么他是无法接收到来自外部的信号的。推荐的方法是用定时器周期触发。

示例代码:

QWorker类:

#ifndef QWORKER_H
#define QWORKER_H

#include <QObject>
#include <QThread>
#include <QDebug>

class QWorker : public QObject
{
    Q_OBJECT
public:
    explicit QWorker(QObject *parent = nullptr);
    ~QWorker();

signals:
    void newData(QByteArray data);    // 将本类内的私有数据通过该信号发射出去,供外部使用

public slots:
    void init();         // 一些必要的初始化操作写在此函数内
    void doWork();       // 一些耗时操作写在此函数内
    void writeData(const char* buf, qint64 len);  // 供外部使用的操作接口
};

#endif // QWORKER_H

#include "qworker.h"

QWorker::QWorker(QObject *parent) : QObject(parent)
{
    qDebug() << __FUNCTION__ << "Thread ID:" << QThread::currentThreadId();
}

QWorker::~QWorker()
{
    qDebug() << __FUNCTION__ << "Thread ID:" << QThread::currentThreadId();
}

void QWorker::init()
{
    qDebug() << __FUNCTION__ << "Thread ID:" << QThread::currentThreadId();
}

void QWorker::doWork()
{
    static int count = 0;
    qDebug() << __FUNCTION__ << "Thread ID:" << QThread::currentThreadId() << ">>>" << count++;
}

void QWorker::writeData(const char* buf, qint64 len)
{
    qDebug() << __FUNCTION__ << "Thread ID:" << QThread::currentThreadId() << ">>>" << QByteArray(buf, len);
}


主线程:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "qworker.h"
#include <QTimer>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
    QWorker* worker;
    QThread* thread;
    QTimer* timer;

signals:
    void writeData(const char* buf, qint64 len);
    void stopWork();
};

#endif // MAINWINDOW_H

#include "mainwindow.h"
#include "ui_mainwindow.h"

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

    qDebug() << __FUNCTION__ << "Thread ID:" << QThread::currentThreadId();

    timer = new QTimer(this);

    thread = new QThread();  // 不要指定parent
    worker = new QWorker();  // 不要指定parent

	// thread的finished和deleteLater相连接后,在thread退出时自动删除thread对象,无需手动delete thread
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); 
    // thread的finished和worker的deleteLater相连接后,在thread退出时自动删除worker对象,无需手动delete worker
    connect(thread, SIGNAL(finished()), worker, SLOT(deleteLater()));
    connect(thread, SIGNAL(started()), worker, SLOT(init()));

    connect(timer, SIGNAL(timeout()), worker, SLOT(doWork()));

    connect(this, SIGNAL(writeData(const char*,qint64)), worker, SLOT(writeData(const char*,qint64)));

    worker->moveToThread(thread);

    thread->start();

    timer->start(1000);  // 1000ms执行一次doWork()
}

MainWindow::~MainWindow()
{
    if(timer->isActive())
    {
        timer->stop();
    }

    if(thread->isRunning())
    {
        thread->quit();
        thread->wait();
    }

    qDebug() << __FUNCTION__ << "Thread ID:" << QThread::currentThreadId();

    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    emit writeData("hello world\r\n", 13);
}


程序界面:

运行后控制台打印信息如下:

可以看到的是,MainWindow和QWorker的构造函数中都显示线程ID为0x336c,而在QWorker的析构函数中显示线程ID为0x22a8,这说明moveToThread确实将worker移动到了thread中;而且还可以看到的是,QWorker的槽函数init、doWork、writeData也都是运行在了子线程中!


ends…

  • 6
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

觉皇嵌入式

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

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

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

打赏作者

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

抵扣说明:

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

余额充值