Qt线程的四种创建方式

本文详细介绍了Qt中四种实现多线程的方法:子线程继承QThread、使用moveToThread、QtConcurrent以及线程池,并展示了如何在子线程中进行数据计算并安全地将结果传递给主线程更新UI,确保界面不卡顿。
摘要由CSDN通过智能技术生成

 Qt中主线程负责界面显示和窗口控件的数据更新,子线程负责逻辑业务处理和数据计算,子线程不能对窗口有任何操作,子线程可通过信号槽来将数据传递给主线程。

1、子线程继承QThread

子线程继承QThread,然后重写run()函数来执行子线程

每一个子业务逻辑都可继承一个QThread来实现多线程

    m_thread = new MyThread;
    connect(m_thread, &MyThread::signalsThreadCalNum, this, [=](int num){
        ui->label->setNum(num);
    });
    connect(ui->pushButton_start, &QPushButton::clicked, m_thread, [=](){
        m_thread->start();
    });
    connect(ui->pushButton_stop, &QPushButton::clicked, this, [=](){
        m_thread->Stop();
    });
class MyThread:public QThread
{
    Q_OBJECT
    //....
protected:
    void run();
}

void MyThread::run()
{
    int n = 0;
    while(n < 100000)
    {
        emit signalsThreadCalNum(n++);
        QThread::usleep(1);
    }
}

2、使用moveToThread

(1)任务类Task需要继承QObject,然后写一个执行任务的函数。

(2)创建一个QThread线程,然后调用moveToThread将对象移动到创建的子线程对象中

(3)启动子线程即可

    //创建子线程
    m_thread = new QThread;
    m_work = new MyWork;
    //将工作的类对象转移到创建的子线程对象中
    m_work->moveToThread(m_thread);

    //启动线程
    m_thread->start();
    //这种写法是错误的,界面卡顿,个人理解:接受者是this,相当于mainwiodnw调用
//    connect(ui->pushButton_start, &QPushButton::clicked, this, [=](){
//        m_work->Work();
//    });
    //ok
    connect(ui->pushButton_start, &QPushButton::clicked, m_work, [=](){
        m_work->Start();
    });

    connect(ui->pushButton_stop, &QPushButton::clicked, this, [=](){
        m_work->Stop();
    });
    connect(m_work, &MyWork::signalsThreadCalNum, this, [=](int num){
        ui->label->setNum(num);
    });
class MyWork:public QObject
{
    //......
}

void MyWork::Work()
{
    int n = 0;
    while(n < 1000)
    {
        if(m_stop)
            break;
        emit signalsThreadCalNum(n++);
        QThread::usleep(1);
    }
}

 3、使用QtConcurrent

(1)pro中需要加上 QT += concurrent

(2)任务类中重写run()函数

    MyThread *mythread = new MyThread;
    connect(ui->pushButton_start, &QPushButton::clicked, this, [=](){
        QtConcurrent::run(mythread, &MyThread::Work);
    });
    connect(mythread, &MyThread::signalsThreadCalNum, this, [=](int num){
        ui->label->setNum(num);
    });
    connect(ui->pushButton_stop, &QPushButton::clicked, this, [=](){
        mythread->Stop();
    });
void MyThread::Work()
{
    m_stop = false;
    int n = 0;
    while(n < 100000)
    {
        if(m_stop)
            break;
        emit signalsThreadCalNum(n++);
        QThread::usleep(1);
    }
}

4、使用线程池

使用QRunnable和QThreadPool

(1)任务类需要继承QRunnable,需要使用信号槽的话可多重继承QObject

(2)重写run函数

(3)使用QThreadPool::globalInstance()->start(QRunable *)来启动线程池

    // 线程池初始化,设置最大线程池数
    QThreadPool::globalInstance()->setMaxThreadCount(4);

    //创建任务
    MyThread *mythread = new MyThread;

    //start启动线程池
    connect(ui->pushButton_start, &QPushButton::clicked, this, [=](){
        QThreadPool::globalInstance()->start(mythread);
        mythread->Start();
    });
    connect(mythread, &MyThread::signalsThreadCalNum, this, [=](int num){
        ui->label->setNum(num);
    });
    connect(ui->pushButton_stop, &QPushButton::clicked, this, [=](){
        mythread->Stop();
    });
/*
 * 线程池使用需要继承QRunnable
*/
class MyThread : public QObject, public QRunnable
{
    //.....
}

MyThread::MyThread(QObject *parent) : QObject(parent), QRunnable()
{
    setAutoDelete(true);
}

void MyThread::run()
{
    m_stop = false;
    int n = 0;
    while(n < 100000)
    {
        if(m_stop)
            break;
        emit signalsThreadCalNum(n++);
        QThread::usleep(1);
    }
}

5、线程池中可不采用多重继承QObject,可采用

QMetaObject::invokeMethod来实现

mainwindow.h中添加 



    Q_INVOKABLE void Show(int num);

 mainwindow.cpp



//mainwindow.cpp

    // 线程池初始化,设置最大线程池数
    QThreadPool::globalInstance()->setMaxThreadCount(4);

    //创建任务
    MyThread *mythread = new MyThread(this);

    //start启动线程池
    connect(ui->pushButton_start, &QPushButton::clicked, this, [=](){
        QThreadPool::globalInstance()->start(mythread);
        mythread->Start();
    });

    connect(ui->pushButton_stop, &QPushButton::clicked, this, [=](){
        mythread->Stop();
    });

void MainWindow::Show(int num)
{
    ui->label->setNum(num);
}

 子线程中

void MyThread::run()
{
    m_stop = false;
    int n = 0;
    while(n < 100000)
    {
//        if(m_stop)
//            break;
        QMetaObject::invokeMethod(m_pObj, "Show", Q_ARG(int, n++));
        //emit signalsThreadCalNum(n++);
        QThread::usleep(1);
    }
}

 

  • 6
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值