Qt多线程常见方法(一)


1、Qt底层线程的使用方法(一)

1.1 QThead

创建和启动线程:

  • 继承QThead,重写run方法
  • 调用start开始执行

关闭线程:

  • 使用标志位关闭线程
  • 调用wait等待线程结束
  • 强制关闭线程

mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>

class MyThread : public QThread
{
    Q_OBJECT
public:
    MyThread(QObject* parent = nullptr);

    void stop();

protected:
    void run();

private:
    bool is_stop = true;
};

#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"
#include <QDebug>

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

}

void MyThread::stop()
{
    is_stop = true;
    bool ok = wait(2000);
    if (ok)
    {
        qDebug() << QString::fromLocal8Bit("等待线程结束成功");
    }
    else
    {
        qDebug() << QString::fromLocal8Bit("等待线程结束失败");
        this->terminate();
        wait(1000);
    }
}

void MyThread::run()
{
    // 模拟数据库查询
    is_stop = false;
    qDebug() << QString::fromLocal8Bit("当前线程id ") << this->currentThreadId();
    for (int i = 0; i < 5; i++)
    {
        qDebug() << QString::fromLocal8Bit("正在查询数据库") << i;
        if (is_stop)
        {
            qDebug() << QString::fromLocal8Bit("终止查询");
            return;
        }
        sleep(1);
    }
    qDebug() << QString::fromLocal8Bit("查询结束");
}


1.2 moveToThread

void QObject::moveToThread(QThread *targetThread)
使用方法:

  1. 定义一个继承于QObject的类,在这个类中可以定义多个槽函数,每个槽函数子线程执行的代码。
  2. QThread* td = tdnew QThread和worker类对象,使用moveToThread(td)将worker中的事件循环交给ttd处理。
  3. 建立信号与槽函数的连接。

UserManager.h:定义两个槽函数,两个信号,声明QThread。

#ifndef USERMANAGER_H
#define USERMANAGER_H

#include <QObject>
#include <QThread>

class UserManager : public QObject
{
    Q_OBJECT
public:
    explicit UserManager();
    ~UserManager();

signals:
    void searchBasicFinished(const QString& name);
    void searchJobFinished(const QString& name);

public slots:
    void searchBasic();
    void searchJob();

private:
    QThread* td;
};

#endif // USERMANAGER_H

UserManager.cpp

#include "usermanager.h"
#include <QDebug>

UserManager::UserManager()
    : QObject{}
{
    td = new QThread();
    moveToThread(td);
    td->start();
    qDebug() << td->currentThreadId();
}

UserManager::~UserManager()
{
    if (td->isRunning())
    {
        td->terminate();
        td->wait(1000);
    }
    delete td;
    td = nullptr;
}

void UserManager::searchBasic()
{
    for (int i = 0; i < 3; i++)
    {
        qDebug() << QString::fromLocal8Bit("查询基本信息 ") << i << QThread::currentThreadId();
        QThread::sleep(1);
    }
    emit searchBasicFinished(QString::fromLocal8Bit("张三"));
}

void UserManager::searchJob()
{
    for (int i = 0; i < 3; i++)
    {
        qDebug() << QString::fromLocal8Bit("查询工作信息 ") << i << QThread::currentThreadId();
        QThread::sleep(1);
    }
    emit searchJobFinished(QString::fromLocal8Bit("Qt工程师"));
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include "usermanager.h"

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

signals:
    void searchBasic();
    void searchJob();

public slots:
    void onSearhBasicFinished(const QString& name);
    void onSearhJobFinished(const QString &name);

private slots:
    void on_btnSearchBasic_clicked();
    void on_btnSearchJob_clicked();

private:
    Ui::Widget *ui;
    UserManager* manager;
};
#endif // WIDGET_H

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

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    manager = new UserManager();
    connect(this, &Widget::searchBasic, manager, &UserManager::searchBasic);
    connect(this, &Widget::searchJob, manager, &UserManager::searchJob);

    connect(manager, &UserManager::searchBasicFinished, this, &Widget::onSearhBasicFinished);
    connect(manager, &UserManager::searchJobFinished, this, &Widget::onSearhJobFinished);
}

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

void Widget::onSearhBasicFinished(const QString &name)
{
    ui->textEditBasic->append(QString::fromLocal8Bit("查询基本信息,已接收:") + name);
}

void Widget::onSearhJobFinished(const QString &name)
{
    ui->textEditJob->append(QString::fromLocal8Bit("查询工作信息,已接收:") + name);
}


void Widget::on_btnSearchBasic_clicked()
{
    // 查询用户基本信息
    emit searchBasic();
    ui->textEditBasic->append(QString::fromLocal8Bit("查询基本信息,已发送"));
}


void Widget::on_btnSearchJob_clicked()
{
    // 查询用户工作信息
    emit searchJob();
    ui->textEditJob->append(QString::fromLocal8Bit("查询工作信息,已发送"));
}


总结

  1. 主线程发出信号,子线程对象的槽函数使用线程来执行
  2. 信号和槽是多对多关系
  3. 信号发出后立即返回,信号会放到队列中依次执行
  4. 槽函数执行完成后,使用信号进行通知

moveToThread比较QThread:
5. QThread只能执行一个run方法
6. 使用moveToThread,一个类可以执行多个方法
7. 如果不是长期运行的线程,推荐使用moveToThread

1.3 QThreadPool

QThreadPool是Qt框架提供的一个用于管理线程池的类,它可以帮助在应用程序中管理并发任务的执行。

  1. 创建QThreadPool对象:
QThreadPool *threadPool = QThreadPool::globalInstance(); // 获取全局线程池实例
  1. 创建自定义的任务类:
    继承自QRunnable或者QObject,并实现run()方法,该方法中包含了任务的执行逻辑。
class MyTask : public QRunnable {
public:
    void run() override {
        // 任务执行逻辑
    }
};
  1. 将任务提交给线程池:
MyTask *task = new MyTask();
threadPool->start(task); // 将任务提交给线程池
  • 等待任务执行完成(可选):
threadPool->waitForDone(); // 等待所有任务执行完成

适用情况:

  • 并发执行多个独立的任务
    如果你有多个任务需要并发执行,并且这些任务之间是相互独立的,那么可以使用QThreadPool来管理这些任务的执行。
  • 避免频繁创建和销毁线程
    使用线程池可以避免频繁地创建和销毁线程,从而减少资源消耗和提高效率。
  • 限制并发执行的任务数量
    可以通过设置线程池的最大线程数来限制并发执行的任务数量,以避免系统资源被过多地占用。
  • 异步任务执行
    如果你需要在后台执行一些耗时的任务,但又不希望阻塞主线程,可以将这些任务提交给线程池来异步执行,从而保持界面的响应性。
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值