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,共同操作 ...
随机推荐
- Qt socket中怎么传结构体?
直接发送和接收结构体,例如:struct A {...};struct A objectA; 发送的时候: tcpSocket->write((char *)&objectA, size ...
- HDU 1090 A+B for Input-Output Practice (II)
#include <cstdio> int main() { int n,a,b; scanf("%d",&n); ; i<=n; i++) { scan ...
- PLSQL 导入表到Oracle------》从一个表空间导入到其它表空间
在用PLSQL导入.dmp文件到Oracle时出现的问题如下: Import started on 2015/11/18 10:42:44E:\oracle\product\10.2.0\db ...
- Java编程思想重点笔记
首先声明转自https://github.com/lanxuezaipiao/ReadingNotes 无意中发现,写的蛮好转过来学习下. 1. Java中的多态性理解(注意与C++区分) Java中 ...
- JavaScript 覆盖document.createElement 方法 解决window.close在火狐下不兼容问题)
近期项目遇到了问题,有个asp.net web程序仅仅能在IE7 执行.如今xp都淘汰了,大家都用IE8-IE11,因此这个web app也须要升级 适应全部IE版本号.照成IE版本号不兼容的问题主要 ...
- HDU 1796 容斥原理 How many integers can you find
题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1796 处男容斥原理 纪念一下 TMD看了好久才明白DFS... 先贴代码后解释 #includ ...
- 关于var(string)++的类型自动转换
展示时间: var miao="50"; var fen="59"; var shi="00"; setInterval(fun, 1000 ...
- 简单JSONP跨域请求
JSONP原理:利用<script>标签的src属性实现跨域的请求.可在URL中提供回调函数的名字.后台进过处理后将数据以回调函数参数的形式返回. demo:JSONP请求不同端口的数据 ...
- 在TextBox里面仅仅允许数字,按Enter键进入下一个TextBox
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> ...
- Unity 对象池 生产 保存
Unity对象池主要是保存那些常用的物体,避免他们在不断销毁和创造中损坏性能. 主要思路为:创造物体时,判断是否存在,如果存在则调用并使其显示.如果不存在则创造一个新的. 当销毁时,调用协程延时隐藏物 ...