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,共同操作 ...
随机推荐
- oracle如何修改字段类型(oracle总体知识2)
在一次做开发的时候,遇到需要将数据表的字段类型由number改成varchar,可是该字段又有值, 用 alter table t-name modify cname newType;会报错. 话说 ...
- javaScript中有关正则表达式的用法总结
js中处理正则表达式的类:RegExp 用法: var reg=new RegExp("express"); 或者: var reg=/express/; js中常用的6个方法: ...
- 电脑cmos是什么?和bois的区别?
很多人都分不清电脑cmos和bois区别,有人一会儿说什么bois设置,有人一会儿说cmos设置.而看起来这两个又似乎差不多,本文将用最简单的白话文告诉各位,什么是cmos,以及cmos和bois的的 ...
- 使用Boost.Asio编写通信程序
摘要:本文通过形像而活泼的语言简单地介绍了Boost::asio库的使用,作为asio的一个入门介绍是非常合适的,可以给人一种新鲜的感觉,同时也能让体验到asio的主要内容. Boost.Asio是一 ...
- Libev学习笔记2
这一节根据官方文档给出的简单示例,深入代码内部,了解其实现机制.示例代码如下: int main (void) { struct ev_loop *loop = EV_DEFAULT; ev_io_i ...
- 如何开始一个模块化可扩展的Web App(转)
原文链接:http://avnpc.com/pages/start-a-modular-extensible-webapp 日志未经声明,均为AlloVince原创.版权采用『 知识共享署名-非商业性 ...
- Modular Inverse(模逆元,扩展欧几里德)
Modular Inverse Time Limit: 2 Seconds Memory Limit: 65536 KB The modular modular multiplicative ...
- Objective-c 程序结构
类是Objective-c的核心,Objective-c程序都是围绕类进行的.Objective-c程序至少包含以下三个部分: 1.类接口:定义了类的数据和方法,但是不包括方法的实现代码. 2.类实现 ...
- C#语言基础之转义字符、变量、常量、类型转换
1.转义字符: Tab键:/t 反斜杠:// 单引号:/’ 双引号:/” 回车:/r 换行:/n 警告:/a 退格:/b 换页:/f 空:/0 2.变量 ...
- C# Best Practices - Creating Good Methods
How to Define a Method Identify the problem => Define the single purpose => Specify the inputs ...