QT——C++ 多线程05

一、创建多线程的方式

QT创建(使用)多线程的方式有三种。

  1. 直接创建QThread 对象,重写run方法,最后调用start方法启动线程。
  2. 通过调用QObject类提供的moveToThread方法实现
  3. 线程池

(一)方式一:

如果需要向run传入参数,或者返回执行结果,可以通过信号和槽机制实现

  • mywork.h
#ifndef MYWORK_H
#define MYWORK_H

#include <QObject>
#include <QThread>

/**
 *    @class   mywork.h
 *
 *    @brief   工作线程
 *
 *
 *    @author:   lihua
 *    @date:     2022-10-25  15:53
 */
class MyWork : public QThread
{
    Q_OBJECT
public:
    explicit MyWork(QThread *parent = nullptr);

signals:
    //信号由子线程发出,主线程接收(子线程返回执行结果给主线程)
    void signalWork(int result);

public slots:
    //信号由主线程发出,子线程接收(主线程传入参数给子线程)
    void slotWork(int num);

    // QThread interface
protected:
    void run();

private:
    int num = 0;

};

#endif // MYWORK_H

  • mywork.cpp
#include "mywork.h"
#include <QDebug>

MyWork::MyWork(QThread *parent) : QThread(parent)
{

}

void MyWork::slotWork(int num)
{
    //调用槽函数
    qDebug()<< "子线程的槽函数被调用"<<num;
    this->num = num;

}

/**
 * @brief 主线程传一个初始值num给子线程,子线程在num的基础上加100
 *
 * @param  run没有参数,num是通过槽函数获取的
 *
 * @return  run没有返回值将计算结果通过槽函数返回给主线程
 */
void MyWork::run()
{

    qDebug()<< "运行子线程<<" << QThread::currentThread();

    //主线程给一个初始值num
    int num = this->num;



    int result = num +100;

    //发出信号,订阅了此信号的订阅者的槽函数会被回调,将计算结果通过槽函数返回给主线程
    qDebug()<< "结果:"<<result;
    emit signalWork(result);


}

  • mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include "mywork.h"

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

private:
    Ui::MainWindow *ui;

    //子线程
    MyWork *thread;

    // 计算结果
    int result;

signals:
    //信号
    void signalMain(int num);

public slots:
    //槽函数
    void slotMain(int result);

};



#endif // MAINWINDOW_H

  • mainwindow.cpp
#include "mainwindow.h"
#include "mywork.h"
#include "ui_mainwindow.h"

#include <QThread>
#include <QDebug>

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

    qDebug()<< QThread::currentThread();

    thread = new MyWork();


    //订阅signalMain信号,并指定回调函数。
    connect(this,&MainWindow::signalMain,thread,&MyWork::slotWork);

    //订阅signalWork信号,并指定回调函数
    //connect(thread,&MyWork::signalWork,this,&MainWindow::slotMain); 也可以用lamda实现
    connect(thread,&MyWork::signalWork,this,[=](int result){

        this->result = result;
        qDebug()<< "result="<<this->result;
    });

    //发出一个信号,将10通过槽函数slotWork传递给run
    emit signalMain(10);

    thread->start();


}

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

void MainWindow::slotMain(int result)
{
    this->result = result;

    qDebug()<< "result="<<this->result;
}

(二)方式二:

更改此对象及其子对象的线程关联。如果对象具有父对象,则无法移动该对象。事件处理将在targetThread中继续。
如果targetThread为零,则此对象及其子对象的所有事件处理都将停止。

请注意,对象的所有活动计时器都将重置。计时器首先在当前线程中停止,然后在targetThread中重新启动(以相同的间隔)。因此,在线程之间不断移动对象会无限期地延迟计时器事件。

在更改线程关联之前,QEvent::ThreadChange事件被发送到此对象。您可以处理此事件以执行任何特殊处理。请注意,任何发布到此对象的新事件都将在targetThread中处理。

警告:此函数不是线程安全的;当前线程必须与当前线程关联性相同。换句话说,此函数只能将对象从当前线程“推”到另一个线程,不能将对象从任意线程“拉”到当前线程

  • mywork1.h
#ifndef MYWORK1_H
#define MYWORK1_H

#include <QObject>

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

    //工作函数
    void work();
signals:
    void curNumber(int  num);

public slots:
};

#endif // MYWORK1_H

  • mywork1.cpp
#include "mywork1.h"

#include <QThread>
#include <QDebug>

MyWork1::MyWork1(QObject *parent) : QObject(parent)
{

}

void MyWork1::work()
{
    qDebug()<< "子线程对象地址:"<<QThread::currentThread() ;

    int num = 0;
        while(1)
        {
            emit curNumber(num++);
            if(num == 1000)
            {
                break;
            }
            QThread::usleep(1);
        }
        qDebug() << "run() 执行完毕, 子线程退出...";
}

  • 核心代码
void MainWindow::testThread()
{
    QThread *thread = new QThread();

    MyWork1 *work = new MyWork1();

    //注意这个方法是QObject提供的,将对象从当前线程“推”到另一个线程运行
    work->moveToThread(thread);
    thread->start();

    //不能直接调用,直接调用还是主线程运行
    //work->work();
    //通过槽机制运行才能将对象交给targetThread运行。
    connect(ui->pushButton,&QPushButton::clicked,work, &MyWork1::work);

    connect(work,&MyWork1::curNumber,this,[=](int num){
        ui->textBrowser->setText(QString::number(num));
    });
}

(三)方式三:

QThreadPool类管理QThreads的集合。
QThreadPool管理和重新设计单个QThread对象,以帮助减少使用线程的程序中的线程创建成本。每个Qt应用程序都有一个全局QThreadPool对象,可以通过调用globalInstance()来访问该对象。
要使用QThreadPool线程之一,请将QRunnable子类化并实现run()虚拟函数。然后创建该类的对象并将其传递给QThreadPool::start()

#include "mywork2.h"
#include <QDebug>
#include <QThread>
MyWork2::MyWork2()
{

}

void MyWork2::run()
{
    qDebug()<< "线程池方式使用多线程。"<<QThread::currentThread();

}

/**
 * @brief 线程池测试
 *
 * @param
 * @param
 *
 * @return
 */
void MainWindow::testThreadPool()
{
    //获取线程池,同时设置最大线程数。
    QThreadPool::globalInstance()->setMaxThreadCount(2);
    MyWork2 *work = new MyWork2();

    QThreadPool::globalInstance()->start(work);
    
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值