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,共同操作 ...
随机推荐
- android 自定义百度地图放大缩小
自定义实现Android百度地图的缩放图标,需要自定义一个缩放控件,实现效果如下: 这里的缩放效果,实现了点击按钮可以对地图的放大缩小,通过手势放大与缩小也控制缩放图标的可用状态.具体实现如下: zo ...
- github 的分支操作
首先需要当前目录设置为仓库目录 一.创建本地分支 1.查看有哪些分支:git branch 2.创建一个分支:git branch name ,其中name是分支名 3.切换到分支:git chec ...
- openScales源码学习系列之 Feature属性
coordinates:当前区域,geometry或Polygon的点集合. countries.国家所在位置下标 SQKM.平方千米 COLOR_MAP.该国家的颜色类别 SQMI.平方英里 CON ...
- Oracle 动态查询,EXECUTE IMMEDIATE select into使用方法
create or replace procedure TEST_TABLE is l_table_name varchar2(50); query_stat varchar2(100); l_zyq ...
- 使用jodconverter和swftools实现文件在线预览
参考:仿百度文库解决方案(四)——利用JODConverter调用OpenOffice.org服务转换文档为PDF 文档在线预览主要用到如下两个工具 1,安装openoffice(同时下载jodcon ...
- A/B(扩展欧几里德)
A/B Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...
- BZOJ 1726: [Usaco2006 Nov]Roadblocks第二短路( 最短路 )
从起点和终点各跑一次最短路 , 然后枚举每一条边 , 更新answer ---------------------------------------------------------------- ...
- 【转载】国内网站博客数据统计选免费Google Analytics还是百度统计
[转载]国内网站博客数据统计选免费Google Analytics还是百度统计 Google Analytics谷歌统计是我用的第一个网站统计工具,当然现在也一直在用.Google Analytics ...
- Nginx 之二: nginx.conf 配置及基本优化
一:常用功能优化: 1:网络连接的优化: 只能在events模块设置,用于防止在同一一个时刻只有一个请求的情况下,出现多个睡眠进程会被唤醒但只能有一个进程可获得请求的尴尬,如果不优化,在多进程的ngi ...
- (Problem 22)Names scores
Using names.txt (right click and 'Save Link/Target As...'), a 46K text file containing over five-tho ...