博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Qt5中运行后台网络读取线程与主UI线程互交
阅读量:5892 次
发布时间:2019-06-19

本文共 2717 字,大约阅读时间需要 9 分钟。

项目中有一个需求就是,因为需要请求服务端数据,因为网络的读取会阻塞,所以该过程不能放在Qt中的UI主线程当中,需要用一个后台线程来读取数据,数据准备完毕后

在通过Qt5中的信号槽机制来跨线程的传递数据。之前的博文使用过moveToThread的方式来讲解创建后台线程,但是现在后台线程需要与前台UI线程数据互交,然而,最悲剧的就是信号发出去了,

但是前台的UI线程对象收不到信号,也就是相应的槽函数没被调用。之前博文后台线程是没有与前台UI线程互交的,因为它是采集数据的线程,只管往目标地址发送数据就可以了。但是接收线程就不一样了,

它需要把后台接收到的网络数据放到前台GUI中展现出来。这不可避免的产生互交和数据的传递。

 

前台的UI线程创建后台线程的代码大概如下:

1  RecvDataObject *recv_obj = new RecvDataObject; 2  3     QThread* backgroundRecvThread = new QThread; 4  5     6      recv_obj->moveToThread(backgroundRecvThread); 7      8     connect(recv_obj, &RecvDataObject::dataRecved, 9         this, &TerminalStatusWidget::slotDataRecved,Qt::QueuedConnection);10    11    12     backgroundRecvThread->start();

 

注意,多线程间的信号槽传递,在connect的时候需要以Qt::QueuedConnection的方式,不然以Qt::DirectConnection的方式接收者UI线程会很长时间收不到后台线程发出的信号,或者信号直接丢失都是有可能的。参考

http://www.qtcentre.org/threads/17764-emit-qt-signal-is-very-slow-how-it-can-be-optimized

 

RecvDataObect是用来接收后台数据的对象被move到了backgroundRecvThread线程中去执行了。其声明是这样的:

1 class RecvDataObject : public QObject 2 { 3     Q_OBJECT 4  5 public: 6     RecvDataObject(); 7     ~RecvDataObject(); 8 signals: 9     void dataRecved(std::vector
list);10 public slots:11 void slotRecvTask();12 private:13 QTimer m_RecvTask;14 15 };

该类的构造函数我采用了一个Timer来循环执行slotRecvTask()的任务,专门创建网络连接,接收网络数据。然后数据接收完毕后,通过发送dataRecved的信号传递到UI主线程中的slot函数中,但是不能正常工作。槽函数一直不能调用。

上网查了原因才知道,原来Qt的信号槽函数只默认支持Qt的类型和C++提供的内建的基本类型,比如int double float啥的,根本不支持C++的std::string std::vector 自定义的struct类型。所以需要用Qt提供的Q_DECLARE_METATYPE和

qRegisterMetaType来声明和注册自定义的类型和C++的其他类型。  所以以上的C++类RecvDataObject应该变成以下:

1 Q_DECLARE_METATYPE(RunTimeInfo) 2 Q_DECLARE_METATYPE(std::vector
) 3 4 class RecvDataObject : public QObject 5 { 6 Q_OBJECT 7 8 public: 9 RecvDataObject()10 {11 qRegisterMetaType
("RunTimeInfo");12 qRegisterMetaType
>("std::vector
");13 14 m_RecvTask.setInterval(5000);15 connect(&m_RecvTask, SIGNAL(timeout()), this, SLOT(slotRecvTask()));16 m_RecvTask.start();17 }18 ~RecvDataObject();19 signals:20 void dataRecved(std::vector
list);21 public slots:22 void slotRecvTask();23 private:24 QTimer m_RecvTask;25 26 };

 

然后主线程的Widget类的构造函数里面还必须加入:

1 qRegisterMetaType
("RunTimeInfo");2 qRegisterMetaType
>("std::vector
");

这样信号槽函数才能正确工作,通过信号槽机制跨线程的数据传递完成了,完美运行。

 

references:

https://stackoverflow.com/questions/638251/how-to-emit-cross-thread-signal-in-qt

http://www.qtcentre.org/threads/54409-signal-slot-with-std-string-How

https://stackoverflow.com/questions/14083599/signals-and-slots-passing-data

 

转载地址:http://jdfsx.baihongyu.com/

你可能感兴趣的文章
《Android Studio应用开发实战详解》——第1章,第1.3节Android系统架构
查看>>
记录一些React的一些细节,会不断更新
查看>>
自己常用的mixin(持续更新)
查看>>
[译] 移动技术在改善财务健康方面的作用
查看>>
播放音频的工具类
查看>>
iOS面试题03-原理篇
查看>>
JavaScript 基础之原型和原型链
查看>>
jvm逃逸分析
查看>>
数组、字符串常用方法
查看>>
前端面试指南
查看>>
【整理】18种推荐的CSS命名和书写规范
查看>>
new命令的原理
查看>>
人工智能:是拿什么向奇点迫近的?
查看>>
南京a货翡翠,天津a货翡翠
查看>>
css3 渐变
查看>>
如何在 JavaScript 中更好地使用数组
查看>>
阿里开发者招聘节 | 面试题01:如何实现一个高效的单向链表逆序输出?
查看>>
只想着一直调用一直爽, 那API凭证泄漏风险如何破?
查看>>
IT软件开发常用英语词汇
查看>>
开年巨制!千人千面回放技术让你“看到”Flutter用户侧问题
查看>>