Qt5中运行后台网络读取线程与主UI线程互交

admin 2022年9月15日12:54:36安全开发评论0 views2286字阅读7分37秒阅读模式
项目中有一个需求就是,因为需要请求服务端数据,因为网络的读取会阻塞,所以该过程不能放在Qt中的UI主线程当中,需要用一个后台线程来读取数据,数据准备完毕后
在通过Qt5中的信号槽机制来跨线程的传递数据。之前的博文使用过moveToThread的方式来讲解创建后台线程,但是现在后台线程需要与前台UI线程数据互交,然而,最悲剧的就是信号发出去了,
但是前台的UI线程对象收不到信号,也就是相应的槽函数没被调用。之前博文后台线程是没有与前台UI线程互交的,因为它是采集数据的线程,只管往目标地址发送数据就可以了。但是接收线程就不一样了,
它需要把后台接收到的网络数据放到前台GUI中展现出来。这不可避免的产生互交和数据的传递。
前台的UI线程创建后台线程的代码大概如下:
RecvDataObject *recv_obj = new RecvDataObject;
QThread* backgroundRecvThread = new QThread;

recv_obj->moveToThread(backgroundRecvThread);
connect(recv_obj, &RecvDataObject::dataRecved, this, &TerminalStatusWidget::slotDataRecved,Qt::QueuedConnection);

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线程中去执行了。其声明是这样的:
class RecvDataObject : public QObject{    Q_OBJECT
public: RecvDataObject(); ~RecvDataObject();signals: void dataRecved(std::vector list);public slots: void slotRecvTask();private: QTimer m_RecvTask;
};
该类的构造函数我采用了一个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应该变成以下:
Q_DECLARE_METATYPE(RunTimeInfo)Q_DECLARE_METATYPE(std::vector)
class RecvDataObject : public QObject{ Q_OBJECT
public: RecvDataObject() { qRegisterMetaType("RunTimeInfo"); qRegisterMetaType<std::vector>("std::vector");
m_RecvTask.setInterval(5000); connect(&m_RecvTask, SIGNAL(timeout()), this, SLOT(slotRecvTask())); m_RecvTask.start(); } ~RecvDataObject();signals: void dataRecved(std::vector list);public slots: void slotRecvTask();private: QTimer m_RecvTask;
};
然后主线程的Widget类的构造函数里面还必须加入:
qRegisterMetaType("RunTimeInfo");qRegisterMetaType<std::vector>("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

Qt5中运行后台网络读取线程与主UI线程互交

Qt5中运行后台网络读取线程与主UI线程互交 - foo__hack - 博客园 (cnblogs.com)

原文始发于微信公众号(汇编语言):Qt5中运行后台网络读取线程与主UI线程互交

特别标注: 本站(CN-SEC.COM)所有文章仅供技术研究,若将其信息做其他用途,由用户承担全部法律及连带责任,本站不承担任何法律及连带责任,请遵守中华人民共和国安全法.
  • 我的微信
  • 微信扫一扫
  • weinxin
  • 我的微信公众号
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年9月15日12:54:36
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                  Qt5中运行后台网络读取线程与主UI线程互交 http://cn-sec.com/archives/1296893.html

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: