Qt多线程的多种方法之一 QThread

QThread 似乎是很难的一个东西,特别是信号和槽。以下仅本人学习过程中写的简单案例。

QThread多线程使用方法

  • QThread类提供了一个与平台无关的管理线程的方法。在Qt中建立线程的主要目的就是为了用线程来处理那些耗时的后台操作,比如大量运算,复制大文件,网络传输等。

  • 使用Qt框架开发应用程序时,使用QThread类可以方便快捷地创建管理多线程。

  • 而多线程之间的通信也可使用Qt特有的“信号-槽”机制实现。

QThread的使用方法有如下两种:

  1. 继承QThread类
  2. QObject::moveToThread()

继承QThread方法

第一种方法很简单,也很好理解,写一个类继承QThread类,并重写run()函数,并在主线程中生成一个ChildThread的实例,并调用对象的start()函数。

界面(.h):

#ifndef THREADDLG_H
#define THREADDLG_H
 
#include <QDialog>
#include <QPushButton>
#include "workthread.h"
#define MAXSIZE 5							//MAXSIZE宏定义了线程的数目
class ThreadDlg : public QDialog
{
    Q_OBJECT
 
public:
    ThreadDlg(QWidget *parent = 0);
    ~ThreadDlg();
private:
    QPushButton *startBtn;
    QPushButton *stopBtn;
    QPushButton *quitBtn;
    workThread *myThread[MAXSIZE];		//创建线程指针数组
public slots:
    void slotStart();						//槽函数用于启动线程
    void slotStop();						//槽函数用于终止线程
};
 
#endif // THREADDLG_H

界面(.cpp):

#include "threaddlg.h"
#include <QHBoxLayout>
ThreadDlg::ThreadDlg(QWidget *parent)
    : QDialog(parent)
{
    setWindowTitle(tr("线程"));
    startBtn = new QPushButton(tr("开始"));
    stopBtn = new QPushButton(tr("停止"));
    quitBtn = new QPushButton(tr("退出"));
 
    QHBoxLayout *mainLayout = new QHBoxLayout(this);
    mainLayout->addWidget(startBtn);
    mainLayout->addWidget(stopBtn);
    mainLayout->addWidget(quitBtn);
 
    connect(startBtn,SIGNAL(clicked()),this,SLOT(slotStart()));
    connect(stopBtn,SIGNAL(clicked()),this,SLOT(slotStop()));
    connect(quitBtn,SIGNAL(clicked()),this,SLOT(close()));
}
 
void ThreadDlg::slotStart()
{
    for(int i=0;i<MAXSIZE;i++)
    {
        myThread[i]=new workThread();	//创建五个线程
    }
    for(int i=0;i<MAXSIZE;i++)
    {
        myThread[i]->start();			//启动这五个线程
    }
    startBtn->setEnabled(false);
    stopBtn->setEnabled(true);
}
 
void ThreadDlg::slotStop()
{
    for(int i=0;i<MAXSIZE;i++)
    {
        myThread[i]->terminate();//结束这五个线程
        myThread[i]->wait();//阻塞等待处理结束
    }
    startBtn->setEnabled(true);
    stopBtn->setEnabled(false);
}
 
ThreadDlg::~ThreadDlg()
{
 
}

线程类:(.h)

#ifndef WORKTHREAD_H
#define WORKTHREAD_H
 
#include <QThread>
 
class workThread:public QThread
{
public:
    workThread();
 
protected:
    void run();
};
 
#endif // WORKTHREAD_H

若想主线程给子线程传递参数,则可以采用构造函数进行交互数据。

线程类:(.cpp)

#include "workthread.h"
#include <QDebug>
#include <QVector>
 
workThread::workThread()
{
 
}
 
void workThread::run()
{
    QVector<int> nums{1,2,4,3,6,4,2,2,23434,554,232,323,54,66};
    int n = nums.size();
    bool isChange = false;
    while (true) {
        for(int i = 1;i<n;i++){
            for(int j = 0;j<n-i-1;j++){
                if(nums[j]>nums[j+1])
                {
                    int t = nums[j];
                    nums[j] = nums[j+1];
                    nums[j+1] = t;
                    isChange = true;
                }
            }
            if(!isChange){
                break;
            }
        }
 
        for(int &n:nums){
            qDebug()<<n<<" ";
        }
    }
}

QObject::moveToThread

说实话这种方法我没有很理解

  1. 定义一个普通的QObject派生类FileWorker,然后将其对象move到QThread中。
  2. 在定义一个转发类也是QObject子类,起名字叫controller,或者叫dummy。将转发类的信号槽和FileWorker类的信号槽关联起来,这样在主线程中调用转发类的槽函数,或者接收信号就OK了。
    大概意思是通过转发类,能使得FileWorker类的槽函数妥当的运行在子线程里面。同时也不需要使用QMutex来进行同步,Qt的事件循环会自己自动处理好这个。

总结

推荐做的:
在QThread子类添加信号。这是绝对安全的,并且也是正确的(发送者的线程依附性没有关系)

不应该做的是:
调用moveToThread(this)函数
指定连接类型:这通常意味着你正在做错误的事情,比如将QThread控制接口与业务逻辑混杂在了一起(而这应该放在该线程的一个独立对象中)
在QThread子类添加槽函数:这意味着它们将在错误的线程被调用,也就是QThread对象所在线程,而不是QThread对象管理的线程。这又需要你指定连接类型或者调用moveToThread(this)函数
使用QThread::terminate()函数

不能做的是:
在线程还在运行时退出程序。使用QThread::wait()函数等待线程结束
在QThread对象所管理的线程仍在运行时就销毁该对象。如果你需要某种“自行销毁”的操作,你可以把finished()信号同deleteLater()槽连接起来

参考:https://blog.csdn.net/zb872676223/article/details/22718087

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值