Qt多线程简述————moveToThread/QThread

0 背景

因为项目需要处理TCP传来的特别快的数据,每秒600次,核算差不多1.6ms一次,如果单用一个主线程来处理特别容易卡死(因为虽然主线程接受数据很快,但是处理数据就会特别慢(相较与接受数据),就会导致来不及接受接下来的数据),因此需要用到多线程来处理。

以前都是单核计算机时,多线程其实都是并发的,也就是(微观上)多个线程轮换使用cpu,宏观上看起来是“同时”执行的,因此总体上效率并没有明显的提升。但是多核计算机时,可以并行(微观上同时)执行多个线程,执行效率会有明显提升。

1 moveToThread自动化管理线程【推荐】

处据的类:

class DealData:public QObject{
    Q_OBJECT
public slots:
    //处理数据函数
    void deal(QString);
signals:
    //把处理后的记过返回给主线程
    void resultReady(const QString);
};
 

主类(主线程):

class Widget : public QWidget
{
    Q_OBJECT

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

private:
    Ui::Widget *ui;
signals:
    //激活线程的槽函数
    void activeThread(QString);
public slots:
    //处理返回后的结果
    void handleResult(QString);
private:
    //管理的线程 
    QThread dealDataThreadOne;
    //初始化线程
    void initDealDataThread();
};

事件处理

#ifdef Q_OS_LINUX
#include <pthread.h>
#endif

#ifdef Q_OS_WIN
#include <windows.h>
#endif

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

#include<QDebug>
#include<QPushButton>
//构造函数
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //输出线程标示
    #ifdef Q_OS_LINUX
    qDebug() << pthread_self();
#endif

#ifdef Q_OS_WIN
    qDebug() << GetCurrentThreadId();
#endif

    //初始化线程
    initDealDataThread();
    //创建一个button,用于激活线程处理函数(也可以使用其他方式)
    QPushButton *pushButton;
    pushButton = new QPushButton(this);
    //设置按钮名
    pushButton->setObjectName(QString::fromUtf8("pushButton"));
    //设置大小
    pushButton->setGeometry(QRect(50, 50, 171, 61));
    //设置按钮中的文字
    pushButton->setText(QCoreApplication::translate("Widget", "\346\277\200\346\264\273\345\244\204\347\220\206\346\225\260\346\215\256\347\232\204\347\272\277\347\250\213", nullptr));
    //button点击时间激活
    connect(pushButton, &QPushButton::clicked, [=](){
        activeThread(QString("jiangxueHan"));
    });

}

Widget::~Widget()
{
    //退出线程
    dealDataThreadOne.quit();//停止事件循环
    dealDataThreadOne.wait();//阻塞知道线程结束
    delete ui;
}

void Widget::initDealDataThread()
{
    DealData* dealdata = new DealData; 
   qDebug()<<"主线程:"<<QThread::currentThreadId();
   
    dealdata->moveToThread(&dealDataThreadOne);
    //把数据处理交给其余线程
    connect(this, &Widget::activeThread, dealdata, &DealData::deal);
    //处理返回后的结果
    connect(dealdata, &DealData::resultReady, this, &Widget::handleResult);
        //线程结束后,销毁线程
    connect(&dealDataThreadOne, &QThread::finished, this, &DealData::deleteLater);
    //线程开始工作
    dealDataThreadOne.start();
    //下面的必须等线程启动后才能执行
        //设置堆栈大小,也可以实用化默认大小
    dealDataThreadOne.setStackSize(4*1024);//4kb大小
    //设置线程优先级
    /*
   QThread::InheritPriority (给创建的线程赋予目前线程同样的等级(默认情况下就为这个)) ,
   QThread::TimeCriticalPriority (尽可能频繁的调度),
    QThread::HighestPriority  >  QThread::HighPriority >  QThread::NormalPriority(操作系统默认的优先级)
   > QThread::LowPriority > QThread::LowestPriority  >QThread::IdlePriority (没有其他线程运行的时候才进行调度)
     */
    dealDataThreadOne.setPriority(QThread::InheritPriority);
    //将当前线程的执行权让给别的可执行线程(由操作系统决定)
   // dealDataThreadOne.yieldCurrentThread();
   
    //设置了一个布尔变量用来标记当前线程的终端状态
    //不设置时为fasle,设置后为true
    //用于用户自行判断中断时使用
    dealDataThreadOne.requestInterruption();
}

//处理主线程发送的数据
void DealData::deal(QString str)
{
    qDebug()<<"处理数据的线程:"<<QThread::currentThreadId();
    emit resultReady(str + ", hello!!");
}

//处理返回的结果
void Widget::handleResult(QString str)
{
    qDebug()<<"线程的中断标志位:"<<dealDataThreadOne.isInterruptionRequested();
    qDebug()<<"result:"<<str;
}
 

2 继承重写QThread

继承重写:

 
class Widget;class MyThread: public QThread{    //允许Widget类访问自己的私有变量    friend class Widget;private:    volatile bool stopped = false;protected:    //线程处理函数    void run() override;public:    //线程停止    void stop();};

重写事件:

//法一:void MyThread::run(){    int i = 0;    while(!stopped){        qDebug()<<QString("%1 : %2").arg("处理线程:").arg(i);        //睡眠函数        usleep(1);//us        msleep(1);//ms        sleep(1);//s        i++;    }}//法二:void MyThread::run(){    int i = 0;    QTimer* timer = new QTimer;    connect(timer, &QTimer::timeout, [&](){//引用捕获i        if(!stopped){            qDebug()<<"处理线程:"<<i;            i++;        }    });    timer->start(1000);    exec();//开启事件循环,不然timer的信号发不出去}
void MyThread::stop(){    stopped = true;}

Widget主类:

class Widget : public QWidget{    Q_OBJECT
public:    Widget(QWidget *parent = nullptr);    ~Widget();
private:    Ui::Widget *ui;};

Widget构造函数:

Widget::Widget(QWidget *parent)    : QWidget(parent)    , ui(new Ui::Widget){    ui->setupUi(this);    //初始化线程    MyThread* myThread = new MyThread;    //开始线程    myThread->start();//调用run函数
    //创建一个button,用于激活线程处理函数(也可以使用其他方式)    QPushButton *pushButton;    pushButton = new QPushButton(this);    //设置按钮名    pushButton->setObjectName(QString::fromUtf8("pushButton"));    //设置大小    pushButton->setGeometry(QRect(50, 50, 171, 61));    //设置按钮中的文字    pushButton->setText(QCoreApplication::translate("Widget", "\346\277\200\346\264\273\345\244\204\347\220\206\346\225\260\346\215\256\347\232\204\347\272\277\347\250\213", nullptr));    //button点击时间激活    connect(pushButton, &QPushButton::clicked, [=](){        qDebug()<<"myThread->stopped:"<<myThread->stopped;          if(myThread->stopped == false){              myThread->stop();          }else{              myThread->stopped = false;              myThread->start();          }    });
}

3 Qt Concurrent

封装了QThread,方便使用。

Qt += concurrent#include <QtConcurrent>

3.1 使用方法:

调用:

QtConcurrent::run(函数名, 参数名1, 参数名2,...);

使用lambda调用:

QFuture<void> future = QtConcurrent::run([=](){..Code..});

获得返回值:

QFuture<函数返回类型> future = QtConcurrent::run(函数名, 参数名1, 参数名2,...);

3.2 常见成员函数

QtConcurrent::map():直接操作容器中的每一项。QtConcurrent::mapped():操作容器中的每一项,将处理结果返回一个新的容器,原容器不变。QtConcurrent::mappedReduced():在 mapped() 的基础上将处理结果进一步传递给一个函数继续处理。
 
//效果同上,但侧重筛选元素QtConcurrent::filter()QtConcurrent::filtered()QtConcurrent::filteredReduced()
 
//阻塞QtConcurrent::blockingMapQtConcurrent::blockingMappedQtConcurrent::blockingMappedReducedQtConcurrent::blockingfilterQtConcurrent::blockingfilteredQtConcurrent::blockingfilteredReduced

注:调试的时候,处理过程是异步的,它不是立即返回。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蝈蝈(GuoGuo)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值