Qt学习:线程间共享数据(使用信号槽传递数据,必须提前使用qRegisterMetaType来注册参数的类型)
Qt线程间共享数据主要有两种方式:
- 使用共享内存。即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的;
- 使用singal/slot机制,把数据从一个线程传递到另外一个线程。
第一种办法在各个编程语言都使用普遍,而第二种方式倒是QT的特有方式,下面主要学习一下这种方式:
在线程之间传递signal与在一个线程内传递signal是不一样的。在一个线程内传递signal时,emit语句会直接调用所有连接的slot并等待到所有slot被处理完;在线程之间传递signal时,slot会被放到队列中(queue),而emit这个signal后会马上返回;默认情况,线程之间使用queue机制,而线程内使用direct机制,但在connect中可以改变这些默认的机制。
- //TextDevice.h
- #ifndef TEXTDEVICE_H
- #define TEXTDEVICE_H
- #include <QThread>
- #include <QString>
- #include <QMutex>
- class TextDevice : public QThread {
- Q_OBJECT
- public:
- TextDevice();
- void run();
- void stop();
- public slots:
- void write(const QString& text);
- private:
- int m_count;
- QMutex m_mutex;
- };
- #endif // TEXTDEVICE_H
- //TextDevice.cpp
- #include <QMutexLocker>
- #include <QDebug>
- #include <QString>
- #include "TextDevice.h"
- TextDevice::TextDevice() {
- m_count = 0;
- }
- void TextDevice::run() {
- exec();
- }
- void TextDevice::stop() {
- quit();
- }
- void TextDevice::write(const QString& text) {
- QMutexLocker locker(&m_mutex);
- qDebug() << QString("Call %1: %2").arg(m_count++).arg(text);
- }
- //TextThread.h
- #ifndef TEXTTHREAD_H
- #define TEXTTHREAD_H
- #include <QThread>
- #include <QString>
- class TextThread : public QThread {
- Q_OBJECT
- public:
- TextThread(const QString& text);
- void run();
- void stop();
- signals:
- void writeText(const QString&);
- private:
- QString m_text;
- bool m_stop;
- };
- #endif // TEXTTHREAD_H
- //TextThread.cpp
- #include "TextThread.h"
- TextThread::TextThread(const QString& text) : QThread() {
- m_text = text;
- m_stop = false;
- }
- void TextThread::stop() {
- m_stop = true;
- }
- void TextThread::run() {
- while(!m_stop) {
- emit writeText(m_text);
- sleep(1);
- }
- }
- //main.cpp
- #include <QApplication>
- #include <QMessageBox>
- #include "TextDevice.h"
- #include "TextThread.h"
- int main(int argc, char** argv) {
- QApplication app(argc, argv);
- //启动线程
- TextDevice device;
- TextThread foo("foo"), bar("bar");
- //把两个线程使用signal/slot连接起来
- QObject::connect(&foo, SIGNAL(writeText(const QString&)), &device, SLOT(write(const QString&)));
- QObject::connect(&bar, SIGNAL(writeText(const QString&)), &device, SLOT(write(const QString&)));
- //启动线程
- foo.start();
- bar.start();
- device.start();
- QMessageBox::information(0, "Threading", "Close me to stop.");
- //停止线程
- foo.stop();
- bar.stop();
- device.stop();
- //等待线程结束
- device.wait();
- foo.wait();
- bar.wait();
- return 0;
- }
上面例子代码可以看出两个线程之间传送了类型为QString的信息。像QString等这些QT本身定义的类型,直接传送即可。但如果是自己定义的类型如果想使用signal/slot来传递的话,则没有这么简单。直接使用的话,会产生下面这种错误:
QObject::connect: Cannot queue arguments of type 'TextAndNumber' (Make sure 'TextAndNumber' is registed using qRegisterMetaType().)
原因:当一个signal被放到队列中(queued)时,它的参数(arguments)也会被一起一起放到队列中(queued起来),这就意味着参数在被传送到slot之前需要被拷贝、存储在队列中(queue)中;为了能够在队列中存储这些参数(argument),Qt需要去construct、destruct、copy这些对象,而为了让Qt知道怎样去作这些事情,参数的类型需要使用qRegisterMetaType来注册(如错误提示中的说明)
步骤:(以自定义TextAndNumber类型为例)
- 自定一种类型,在这个类型的顶部包含:#include <QMetaType>
- 在类型定义完成后,加入声明:Q_DECLARE_METATYPE(TextAndNumber);
- 在main()函数中注册这种类型:qRegisterMetaType<TextAndNumber>("TextAndNumber");
- 如果还希望使用这种类型的引用,可同样要注册:qRegisterMetaType<TextAndNumber>("TextAndNumber&");
- //TextAndNumber.h
- #ifndef TEXTANDNUMBER_H
- #define TEXTANDNUMBER_H
- #include <QMetaType>
- //必须包含QMetaType,否则会出现下面错误:
- //error: expected constructor, destructor, or type conversion before ‘;’ token
- #include <QString>
- class TextAndNumber {
- public:
- TextAndNumber();
- TextAndNumber(int, QString);
- int count();
- QString text();
- private:
- int m_count;
- QString m_text;
- };
- Q_DECLARE_METATYPE(TextAndNumber);
- #endif // TEXTANDNUMBER_H
- //TextAndNumber.cpp
- #include "TextAndNumber.h"
- TextAndNumber::TextAndNumber() {
- }
- TextAndNumber::TextAndNumber(int count, QString text) {
- m_count = count;
- m_text = text;
- }
- int TextAndNumber::count() {
- return m_count;
- }
- QString TextAndNumber::text() {
- return m_text;
- }
- //TextDevice.h
- #ifndef TEXTDEVICE_H
- #define TEXTDEVICE_H
- #include <QThread>
- #include <QDebug>
- #include <QString>
- #include "TextAndNumber.h"
- class TextDevice : public QThread {
- Q_OBJECT
- public:
- TextDevice();
- void run();
- void stop();
- public slots:
- void write(TextAndNumber& tran);
- private:
- int m_count;
- };
- #endif // TEXTDEVICE_H
- //TextDevice.cpp
- #include "TextDevice.h"
- TextDevice::TextDevice() : QThread() {
- m_count = 0;
- }
- void TextDevice::run() {
- exec();
- }
- void TextDevice::stop() {
- quit();
- }
- void TextDevice::write(TextAndNumber& tran) {
- qDebug() << QString("Call %1 (%3): %2").arg(m_count++).arg(tran.text()).arg(tran.count());
- }
- //TextThread.h
- #ifndef TEXTTHREAD_H
- #define TEXTTHREAD_H
- #include <QThread>
- #include <QString>
- #include "TextAndNumber.h"
- class TextThread : public QThread {
- Q_OBJECT
- public:
- TextThread(const QString& text);
- void run();
- void stop();
- signals:
- void writeText(TextAndNumber& tran);
- private:
- QString m_text;
- int m_count;
- bool m_stop;
- };
- #endif // TEXTTHREAD_H
- //TextThread.cpp
- #include "TextThread.h"
- TextThread::TextThread(const QString& text) : QThread() {
- m_text = text;
- m_stop = false;
- m_count = 0;
- }
- void TextThread::run() {
- while(!m_stop) {
- TextAndNumber tn(m_count++, m_text);
- emit writeText(tn);
- sleep(1);
- }
- }
- void TextThread::stop() {
- m_stop = true;
- }
- //main.cpp
- #include <QApplication>
- #include <QMessageBox>
- #include "TextThread.h"
- #include "TextDevice.h"
- #include "TextAndNumber.h"
- int main(int argc, char *argv[])
- {
- QApplication app(argc, argv);
- qRegisterMetaType<TextAndNumber>("TextAndNumber");
- qRegisterMetaType<TextAndNumber>("TextAndNumber&");
- TextDevice device;
- TextThread foo("foo"), bar("bar");
- QObject::connect(&foo, SIGNAL(writeText(TextAndNumber&)), &device, SLOT(write(TextAndNumber&)));
- QObject::connect(&bar, SIGNAL(writeText(TextAndNumber&)), &device, SLOT(write(TextAndNumber&)));
- device.start();
- foo.start();
- bar.start();
- QMessageBox::information(0, "Threading", "Click me to close");
- foo.stop();
- bar.stop();
- device.stop();
- foo.wait();
- bar.wait();
- device.wait();
- qDebug() << "Application end.";
- return 0;
- }
http://blog.csdn.net/swingline/article/details/5635288
Qt学习:线程间共享数据(使用信号槽传递数据,必须提前使用qRegisterMetaType来注册参数的类型)的更多相关文章
- [转]QT子线程与主线程的信号槽通信-亲测可用!
近用QT做一个服务器,众所周知,QT的主线程必须保持畅通,才能刷新UI.所以,网络通信端采用新开线程的方式.在涉及到使用子线程更新Ui上的控件时遇到了点儿麻烦.网上提供了很多同一线程不同类间采用信号槽 ...
- Qt 学习之路:深入 Qt5 信号槽新语法
在前面的章节(信号槽和自定义信号槽)中,我们详细介绍了有关 Qt 5 的信号槽新语法.由于这次改动很大,许多以前看起来不是问题的问题接踵而来,因此,我们用单独的一章重新介绍一些 Qt 5 的信号槽新语 ...
- 详解 Qt 线程间共享数据(用信号槽方式)
使用共享内存.即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的. Qt 线程间共享数据是本文介绍的内容,多的不说,先来啃内容.Qt线程间共享 ...
- 详解 Qt 线程间共享数据(使用signal/slot传递数据,线程间传递信号会立刻返回,但也可通过connect改变)
使用共享内存.即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的. Qt 线程间共享数据是本文介绍的内容,多的不说,先来啃内容.Qt线程间共享 ...
- Disruptor 线程间共享数据无需竞争
队列的作用是缓冲 缓冲到 队列的空间里.. 线程间共享数据无需竞争 原文 地址 作者 Trisha 译者:李同杰 LMAX Disruptor 是一个开源的并发框架,并获得2011 Duke’ ...
- Qt 学习之路 2(14):对话框数据传递
Home / Qt 学习之路 2 / Qt 学习之路 2(14):对话框数据传递 Qt 学习之路 2(14):对话框数据传递 豆子 2012年9月15日 Qt 学习之路 2 53条评论 对话框 ...
- ThreadLocal实现session中用户信息 的线程间共享(精)
ThreadLocal并不难理解,我总结的最简单的理解就是: ThreadLocal像其它变量一样(局部.全局.静态)也是一种变量类型,只是他是线程变量,更直白的说他是一种变量作用域,即他的作用域是当 ...
- ThreadLocal实现session中用户信息 的线程间共享
转载自:http://blog.sina.com.cn/s/blog_4b5bc01101013gok.html ThreadLocal并不难理解,我总结的最简单的理解就是: ThreadLocal像 ...
- Java并发基础09. 多个线程间共享数据问题
先看一个多线程间共享数据的问题: 设计四个线程,其中两个线程每次对data增加1,另外两个线程每次对data减少1. 从问题来看,很明显涉及到了线程间通数据的共享,四个线程共享一个 data,共同操作 ...
随机推荐
- 【转】context和getApplicationContext()介绍
在android中常常会遇到与context有关的内容,大多都是作为参数在传递,但是它的作用究竟是什么呢 先说它的用法,举个例子 在语句 AlertDialog.Builder builder = n ...
- JS 深拷贝
使用递归进行深拷贝 http://lingyu.wang/2014/03/20/js-interview-1/ Object.prototype.deepClone = function() { va ...
- Word2007中如何插入参考文献
很多国内的期刊杂志都只能使用word模板,导致插入参考文献成了件麻烦事,这时特别怀念Latex的便捷.于是找到一篇介绍word2007里插入参考文献的好方法,就是利用尾注的方法使文章的参考文献标号可以 ...
- Protel99Se使用方法详解
Protel99SE是应用于Windows9X/2000/NT操作系统下的EDA设计软件,采用设计库管理模式,可以进行联网设计,具有很强的数据交换能力和开放性及3D模拟功能,是一个32位的设计软件,可 ...
- rsync、ssh备份
Linux系统需求 为了实现这个备份程序,需要准备一个外部驱动器.您可以将备份写到一个外部USB磁盘,但这样做效率不高.因此,我假设您将备份写到位于网络某处的服务器中.这台服务器要为带有SSH和rsy ...
- MFC消息截获之pretranslatemessage
前几天,查了一个batch的问题,问题大致是这样,父窗口消息一个鼠标消息,弹出一个模态框,CPU负荷就飚升到100%(双核就是50%),非常怪异,用windbg,分析哪个线程占用CPU,定位到鼠标响应 ...
- Windows Azure 网站上的 WordPress 3.8
编辑人员注释:本文章由 Windows Azure 网站团队的项目经理 Sunitha Muthukrishna 和 Windows Azure 网站开发人员体验合作伙伴共同撰写. WordPr ...
- A2W和W2A :很好的多字节和宽字节字符串的转换宏
以前看<Window核心编程>,感觉多字节和宽字节之间还比较麻烦的,至少MultiByteToWideChar函数和WideCharToMultiByte函数有足够多的参数的意义让我们去理 ...
- c++的正整数高精度加减乘除
数值计算之高精度加减乘除 一. 高精度正整数的高精度计算 1.加法 2.减法 减法和加法的最大区别在于:减法是从高位开始相减,而加法是从低位开始相加 3.乘法:用高精度加法实现 l 乘法的主 ...
- 使用jetty和mongodb实现简易网盘接口
依赖库: 1,jetty(提供http方式接口) 2,mongodb的java驱动(访问mongodb存取文件) 3,thumbnailator包,进行缩略图生成 4,commons-fileuplo ...