Qt中线程的推荐用法

在Qt项目中,不可避免的会使用到线程,而在Qt的官方文档中,只有继承QThread重写run函数的用法。

在实际应用中,发现该用法不够灵活,虽然使用run也能实现项目要求,但代码量却要多很多,而且不可避免的会破坏类的封装性,因为一个thread只能做一件事情。

并且,对于继承自QThread类的用法,thread(此时函数工作在线程对象中)对象依旧会有调用线程创建(通常都是主线程),而只有run函数中的内容才在子线程中执行,对于有强迫症的人来说,这是难以接受的。并且这种写法,有的时候会带来线程间对象调用和槽机制的异常等诸多问题。

所以,推荐使用如下方法来优雅的使用线程:

1、在调用线程中(通常是主线程)创建一个工作对象QWorker(执行想要做的事情);

2、在调用线程中(通常是主线程)创建一个QThread对象;

3、调用worker->moveToThread方法,将worker关联到thread对象中。

需要注意的是,thread对象是线程的管理对象,其必须存在与它的调用线程中,不能将其move,反正也move不成功的。

代码大致如下,copy肯定是运行不了的,仅供参考:

1、先是工作对象:

定义:

#ifndef QWORKER_H
#define QWORKER_H

#include <QObject>

class QTime;
class QTimer;
class qDebug;
class QThread;

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

signals:
    void SignalElapsed(int iElapsed);
    void SignalCnt(int iCnt);

public slots:
    void Start(int iTimer,int iTotal);
    void Stop();

    void Exec();

private:
    QTimer *m_pTimer;
    int m_iTotal;
    int m_iCnt;
    int m_iExec;
    QTime m_oTime;
    bool m_bFlag;


};

#endif // QWORKER_H
实现:

#include <QTime>
#include <QTimer>
#include <QDebug>
#include <QThread>
#include "QWorker.h"

QWorker::QWorker(QObject *parent) :
    QObject(parent)
{
    qDebug() << "worker QWorker at " << QThread::currentThreadId();
    m_pTimer = NULL;
    m_iTotal = 0;
    m_iCnt = 0;
    m_iExec = 0;
    m_pTime = NULL;
    m_bFlag = false;
    m_pTimer = new QTimer(this);
}

QWorker::~QWorker()
{
    qDebug() << "worker ~QWorker at " << QThread::currentThreadId();
}

void QWorker::Start(int iTimer, int iTotal)
{
    qDebug() << "worker start at " << QThread::currentThreadId();
    if(NULL != m_pTimer)
    {
        connect(m_pTimer,SIGNAL(timeout()),this,SLOT(Exec()));
        m_pTimer->start(iTimer);
    }
    if(NULL != m_pTime)
    {
        m_pTime->start();
    }
    m_iTotal = iTotal;
}

void QWorker::Stop()
{
    qDebug() << "worker stop at " << QThread::currentThreadId();
    m_iTotal = 0;
    m_iCnt = 0;
    m_iExec = 0;
}

void QWorker::Exec()
{
    if(!m_bFlag)
    {
        qDebug() << "worker exec at " << QThread::currentThreadId();
        m_bFlag = true;
    }

    if(NULL != m_oTime)
    {
        int iElapsed = m_oTime.elapsed();
        emit SignalElapsed(iElapsed);
    }
    while((m_iExec++) < m_iTotal)
    {
        m_iCnt++;
    }
    m_iExec = 0;
    emit SignalCnt(m_iCnt);
    if(NULL != m_oTime)
    {
        m_oTime.restart();
    }
}

2、然后是在主线中,使用线程和工作对象:

定义:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

class QThread;
class QWorker;

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

signals:
    void SignalStart(int iTimer,int iTotal);
    void SignalStop();

private slots:
    void OnCnt(int iCnt);
    void OnElapsed(int iElapsed);
    void on_m_pBtnStart_clicked();
    void on_m_pBtnStop_clicked();

private:
    Ui::MainWindow *ui;

    QThread *m_pThread;
    QWorker *m_pWorker;

    int m_iLastElapsed;
};

#endif // MAINWINDOW_H
实现:

#include <QThread>
#include "QWorker.h"
#include "MainWindow.h"
#include "ui_MainWindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    qDebug() << "window MainWindow at " << QThread::currentThreadId();

    ui->setupUi(this);

    m_pThread = NULL;
    m_pWorker = NULL;

    m_iLastElapsed = 0;

    m_pThread = new QThread(this);
    m_pWorker = new QWorker();
    if(NULL != m_pThread && NULL != m_pWorker)
    {
        connect(m_pWorker,SIGNAL(SignalCnt(int)),this,SLOT(OnCnt(int)));
        connect(m_pWorker,SIGNAL(SignalElapsed(int)),this,SLOT(OnElapsed(int)));
        connect(this,SIGNAL(SignalStart(int,int)),m_pWorker,SLOT(Start(int,int)));
        connect(this,SIGNAL(SignalStop()),m_pWorker,SLOT(Stop()));
        m_pWorker->moveToThread(m_pThread);
    }
}

MainWindow::~MainWindow()
{
    qDebug() << "window ~MainWindow at " << QThread::currentThreadId();

    delete ui;
}

void MainWindow::on_m_pBtnStart_clicked()
{
    if(NULL != m_pThread && NULL != m_pWorker)
    {
        qDebug() << "window start at " << QThread::currentThreadId();
        m_pThread->start();//必须先启动线程事件驱动,否则无法接收信号
        emit SignalStart(ui->m_pEdtTimer->text().toInt(),ui->m_pEdtCnt->text().toInt());
    }
}

void MainWindow::on_m_pBtnStop_clicked()
{
    qDebug() << "window stop at " << QThread::currentThreadId();
    emit SignalStop();
    if(NULL != m_pThread)
    {
        m_pThread->wait(10);
        m_pThread->quit();
        m_pThread->wait(10);
    }
}

void MainWindow::OnCnt(int iCnt)
{
    ui->m_pLabel1->setText(QString::number(iCnt));
}

void MainWindow::OnElapsed(int iElapsed)
{
    ui->m_pLabel2->setText(QString::number(iElapsed));
    if(m_iLastElapsed != iElapsed)
    {
        m_iLastElapsed = iElapsed;
        ui->m_pLabel3->setText(QString::number(m_iLastElapsed));
    }
}







  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值