详解 Qt 线程间共享数据(使用signal/slot传递数据,线程间传递信号会立刻返回,但也可通过connect改变)

使用共享内存。即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的。

Qt 线程间共享数据是本文介绍的内容,多的不说,先来啃内容。Qt线程间共享数据主要有两种方式:

使用共享内存。即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的;

使用singal/slot机制,把数据从一个线程传递到另外一个线程。

第一种办法在各个编程语言都使用普遍,而第二种方式倒是QT的特有方式,下面主要学习一下这种方式:

在线程之间传递signal与在一个线程内传递signal是不一样的。在一个线程内传递signal时,emit语句会直接调用所有连接的slot并等待到所有slot被处理完;在线程之间传递signal时,slot会被放到队列中(queue),而emit这个signal后会马上返回;默认情况,线程之间使用queue机制,而线程内使用direct机制,但在connect中可以改变这些默认的机制。

  1 view plaincopy to clipboardprint?    2 //TextDevice.h      3 #ifndef TEXTDEVICE_H      4 #define TEXTDEVICE_H      5 #include <QThread>      6 #include <QString>      7 #include <QMutex>       8 class TextDevice : public QThread {       9     Q_OBJECT      10 public:      11     TextDevice();      12     void run();      13     void stop();      14 public slots:      15     void write(const QString& text);      16 private:      17     int m_count;      18     QMutex m_mutex;      19 };     20 #endif // TEXTDEVICE_H      21      22      23 //TextDevice.cpp     24 #include <QMutexLocker>     25 #include <QDebug>     26 #include <QString>     27 #include "TextDevice.h"      28 TextDevice::TextDevice() {      29     m_count = 0;      30 }      31 void TextDevice::run() {      32     exec();      33 }      34 void TextDevice::stop() {      35     quit();      36 }      37 void TextDevice::write(const QString& text) {      38     QMutexLocker locker(&m_mutex);      39     qDebug() << QString("Call %1: %2").arg(m_count++).arg(text);      40 }      41      42 //TextThread.h     43 #ifndef TEXTTHREAD_H     44 #define TEXTTHREAD_H     45 #include <QThread>     46 #include <QString>      47 class TextThread : public QThread {      48     Q_OBJECT      49 public:      50     TextThread(const QString& text);      51     void run();      52     void stop();      53 signals:      54     void writeText(const QString&);      55 private:      56     QString m_text;      57     bool m_stop;      58 };     59 #endif // TEXTTHREAD_H      60      61 //TextThread.cpp     62 #include "TextThread.h"      63 TextThread::TextThread(const QString& text) : QThread() {      64     m_text = text;      65     m_stop = false;      66 }      67 void TextThread::stop() {      68     m_stop = true;      69 }      70 void TextThread::run() {      71     while(!m_stop) {      72         emit writeText(m_text);      73         sleep(1);      74     }      75 }      76      77 //main.cpp     78 #include <QApplication>     79 #include <QMessageBox>     80 #include "TextDevice.h"     81 #include "TextThread.h"      82      83 int main(int argc, char** argv) {      84     QApplication app(argc, argv);      85     //启动线程      86     TextDevice device;      87     TextThread foo("foo"), bar("bar");      88     //把两个线程使用signal/slot连接起来      89     QObject::connect(&foo, SIGNAL(writeText(const QString&)), &device, SLOT(write(const QString&)));      90     QObject::connect(&bar, SIGNAL(writeText(const QString&)), &device, SLOT(write(const QString&)));      91     //启动线程      92     foo.start();      93     bar.start();      94     device.start();      95     QMessageBox::information(0, "Threading", "Close me to stop.");      96     //停止线程      97     foo.stop();      98     bar.stop();      99     device.stop();     100     //等待线程结束     101     device.wait();     102     foo.wait();     103     bar.wait();     104     return 0;     105 }    106 //TextDevice.h  107 #ifndef TEXTDEVICE_H  108 #define TEXTDEVICE_H  109 #include <QThread> 110 #include <QString> 111 #include <QMutex> 112 class TextDevice : public QThread {  113     Q_OBJECT  114 public:  115     TextDevice();  116     void run();  117     void stop();  118 public slots:  119     void write(const QString& text);  120 private:  121     int m_count;  122     QMutex m_mutex;  123 };  124 #endif // TEXTDEVICE_H  125  126  127 //TextDevice.cpp  128 #include <QMutexLocker> 129 #include <QDebug> 130 #include <QString> 131 #include "TextDevice.h"  132 TextDevice::TextDevice() {  133     m_count = 0;  134 }  135 void TextDevice::run() {  136     exec();  137 }  138 void TextDevice::stop() {  139     quit();  140 }  141 void TextDevice::write(const QString& text) {  142     QMutexLocker locker(&m_mutex);  143     qDebug() << QString("Call %1: %2").arg(m_count++).arg(text);  144 }  145  146 //TextThread.h  147 #ifndef TEXTTHREAD_H  148 #define TEXTTHREAD_H  149 #include <QThread> 150 #include <QString> 151 class TextThread : public QThread {  152     Q_OBJECT  153 public:  154     TextThread(const QString& text);  155     void run();  156     void stop();  157 signals:  158     void writeText(const QString&);  159 private:  160     QString m_text;  161     bool m_stop;  162 };  163 #endif // TEXTTHREAD_H  164  165 //TextThread.cpp  166 #include "TextThread.h"  167 TextThread::TextThread(const QString& text) : QThread() {  168     m_text = text;  169     m_stop = false;  170 }  171 void TextThread::stop() {  172     m_stop = true;  173 }  174 void TextThread::run() {  175     while(!m_stop) {  176         emit writeText(m_text);  177         sleep(1);  178     }  179 }  180  181 //main.cpp  182 #include <QApplication> 183 #include <QMessageBox> 184 #include "TextDevice.h"  185 #include "TextThread.h"  186 int main(int argc, char** argv) {  187     QApplication app(argc, argv);  188     //启动线程  189     TextDevice device;  190     TextThread foo("foo"), bar("bar");  191     //把两个线程使用signal/slot连接起来  192     QObject::connect(&foo, SIGNAL(writeText(const QString&)), &device, SLOT(write(const QString&)));  193     QObject::connect(&bar, SIGNAL(writeText(const QString&)), &device, SLOT(write(const QString&)));  194     //启动线程  195     foo.start();  196     bar.start();  197     device.start();  198     QMessageBox::information(0, "Threading", "Close me to stop.");  199     //停止线程  200     foo.stop();  201     bar.stop();  202     device.stop();  203     //等待线程结束  204     device.wait();  205     foo.wait();  206     bar.wait();  207     return 0;  208 } 

  上面例子代码可以看出两个线程之间传送了类型为QString的信息。像QString等这些QT本身定义的类型,直接传送即可。但如果是自己定义的类型如果想使用signal/slot来传递的话,则没有这么简单。直接使用的话,会产生下面这种错误:

1 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&");

  1 view plaincopy to clipboardprint?    2 //TextAndNumber.h       3 #ifndef TEXTANDNUMBER_H       4 #define TEXTANDNUMBER_H       5 #include <QMetaType>       6 //必须包含QMetaType,否则会出现下面错误:       7 //error: expected constructor, destructor, or type conversion before ‘;’ token       8 #include <QString>       9 class TextAndNumber {      10 public:      11     TextAndNumber();      12     TextAndNumber(int, QString);      13     int count();      14     QString text();      15 private:      16     int m_count;      17     QString m_text;      18 };      19 Q_DECLARE_METATYPE(TextAndNumber);      20 #endif // TEXTANDNUMBER_H      21      22 //TextAndNumber.cpp      23 #include "TextAndNumber.h"      24 TextAndNumber::TextAndNumber() {      25 }      26 TextAndNumber::TextAndNumber(int count, QString text) {      27     m_count = count;      28     m_text = text;      29 }      30 int TextAndNumber::count() {      31     return m_count;      32 }      33 QString TextAndNumber::text() {      34     return m_text;      35 }      36      37 //TextDevice.h      38 #ifndef TEXTDEVICE_H      39 #define TEXTDEVICE_H      40 #include <QThread>      41 #include <QDebug>      42 #include <QString>      43 #include "TextAndNumber.h"      44 class TextDevice : public QThread {      45     Q_OBJECT      46 public:      47     TextDevice();      48     void run();      49     void stop();      50 public slots:      51     void write(TextAndNumber& tran);      52 private:      53     int m_count;      54 };      55 #endif // TEXTDEVICE_H      56      57 //TextDevice.cpp      58 #include "TextDevice.h"      59 TextDevice::TextDevice() : QThread() {      60     m_count = 0;      61 }      62 void TextDevice::run() {      63     exec();      64 }      65 void TextDevice::stop() {      66     quit();      67 }      68 void TextDevice::write(TextAndNumber& tran) {      69     qDebug() << QString("Call %1 (%3): %2").arg(m_count++).arg(tran.text()).arg(tran.count());      70 }      71      72 //TextThread.h      73 #ifndef TEXTTHREAD_H      74 #define TEXTTHREAD_H      75 #include <QThread>      76 #include <QString>      77 #include "TextAndNumber.h"      78 class TextThread : public QThread {      79     Q_OBJECT      80 public:      81     TextThread(const QString& text);      82     void run();      83     void stop();      84 signals:      85     void writeText(TextAndNumber& tran);      86 private:      87     QString m_text;      88     int m_count;      89     bool m_stop;      90 };      91      92 #endif // TEXTTHREAD_H      93      94 //TextThread.cpp      95 #include "TextThread.h"      96 TextThread::TextThread(const QString& text) : QThread() {      97     m_text = text;      98     m_stop = false;      99     m_count = 0;     100 }     101 void TextThread::run() {     102     while(!m_stop) {     103         TextAndNumber tn(m_count++, m_text);     104         emit writeText(tn);     105         sleep(1);     106     }     107 }     108 void TextThread::stop() {     109     m_stop = true;     110 }     111     112 //main.cpp     113 #include <QApplication>     114 #include <QMessageBox>     115 #include "TextThread.h"     116 #include "TextDevice.h"     117 #include "TextAndNumber.h"     118 int main(int argc, char *argv[])     119 {     120     QApplication app(argc, argv);     121     qRegisterMetaType<TextAndNumber>("TextAndNumber");     122     qRegisterMetaType<TextAndNumber>("TextAndNumber&");     123     TextDevice device;     124     TextThread foo("foo"), bar("bar");     125     QObject::connect(&foo, SIGNAL(writeText(TextAndNumber&)), &device, SLOT(write(TextAndNumber&)));     126     QObject::connect(&bar, SIGNAL(writeText(TextAndNumber&)), &device, SLOT(write(TextAndNumber&)));     127     device.start();     128     foo.start();     129     bar.start();     130     QMessageBox::information(0, "Threading", "Click me to close");     131     foo.stop();     132     bar.stop();     133     device.stop();     134     foo.wait();     135     bar.wait();     136     device.wait();     137     qDebug() << "Application end.";     138     return 0;     139 }   

http://www.cnblogs.com/bingcaihuang/archive/2011/07/14/2106885.html

时间: 2024-11-01 06:42:03

详解 Qt 线程间共享数据(使用signal/slot传递数据,线程间传递信号会立刻返回,但也可通过connect改变)的相关文章

详解Qt动画框架(2)--- 实现网易云音乐tag切换

在详解Qt的动画框架(一)介绍了关于Qt动画框架一些基础知识,在这一节中,将会实际的看到有关与动画框架的实现,该案例主要实现的具体是网易云音乐tag的切换,网易云音乐中的切换如图所示: 本文介绍的方法也可以达到这种切换的简易效果. 设计动画框架 首先我们需要设计对于动画框架,其需要的动画效果是什么?对于上图,我们需要的是三个tag可以不停的切换,可以抽象为左移以及右移,即一个tag从一个矩形区域,移动到另外的矩形区域,那么对于Tag的承载体选为什么较为合适呢?因为我们仅仅只需要图片的显示,因此Q

详解javaweb中jstl如何循环List中的Map数据_java - JAVA

文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 详解javaweb中jstl如何循环List中的Map数据 第一种方式: 1:后台代码(测试) List<Map<String, Object>> list = new ArrayList<Map<String,Object>>(); Map<String, Object> map = null; for (int i = 0; i < 4; i++) { ma

详解 Qt 线程间共享数据(用信号槽方式)

使用共享内存.即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的. Qt 线程间共享数据是本文介绍的内容,多的不说,先来啃内容.Qt线程间共享数据主要有两种方式: 使用共享内存.即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的: 使用singal/slot机制,把数据从一个线程传递到另外一个线程. 第一种办法在各个编程语言都使用普遍,而第二种方式倒是QT的特有方式,下面主要学习一

详解Qt的动画框架(一)

Qt的动画框架是在4.6版本引入的.通过Qt动画属性,Qt动画框架为部件和其他QObject对象的动画操作提供了非常大的自由性.Qt动画框架也能用于图形视图框架中.以下是Qt中的有关动画框架类的类视图: Qt的动画框架的Base是由QAbstactionAnimation以及它的两个子类QVariantAnimation和QAnimationGroup组成.QAbstractAnimation类是所有动画类的祖先.它包含了一些在框架中被普遍使用的基本功能:尤其是启动.停止和暂停动画功能.它也接收

详解DHCP工作方法,并用wireshark对DHCP四个数据包抓包分析

原文地址:http://www.ctowhy.com/395.html DHCP的作用: 在局域网中,用户电脑都需要IP地址才使用网络服务,但是客户并不都会配置IP地址,这时,可以在网络中部署一个DHCP服务器,用来给这些客户主机动态的分配IP. 所有DHCP的客户端,在向DHCP服务器租用到地址后,会在DHCP服务器端留下租用信息,网络管理员可以根据这些分配信息统一管理这些客户. DHCP的一些概念: DHCP是一个典型的Client/Server模型的协议,使用UDP传输 DHCP Serv

QT 中 关键字讲解(emit,signal,slot)

Qt中的类库有接近一半是从基类QObject上继承下来,信号与反应槽(signals/slot)机制就是用来在QObject类或其子类间通讯的方法.作为一种通用的处理机制,信号与反应槽非常灵活,可以携带任意数量的参数,参数的类型也由用户自定.同时其本身也是类型安全的,任何一个从QObject或其子类继承的用户类都可以使用信号与反应槽. 信号的作用如同Windows系统中的消息.在Qt中,对于发出信号的对象来说,它并不知道是谁接收了这个信号.这样的设计可能在某些地方会有些不便,但却杜绝了紧耦合,于

POSIX 线程详解(经典必看)

总共三部分: 第一部分:POSIX 线程详解                                   Daniel Robbins ([email protected]), 总裁/CEO, Gentoo Technologies, Inc.  2000 年 7 月 01 日 第二部分:通用线程:POSIX 线程详解,第 2部分       Daniel Robbins ([email protected]), 总裁/CEO, Gentoo Technologies, Inc.  20

Qt Quick 之 QML 与 C++ 混合编程详解

Qt Quick 技术的引入,使得你能够快速构建 UI ,具有动画.各种绚丽效果的 UI 都不在话下.但它不是万能的,也有很多局限性,原来 Qt 的一些技术,比如低阶的网络编程如 QTcpSocket ,多线程,又如 XML 文档处理类库 QXmlStreamReader / QXmlStreamWriter 等等,在 QML 中要么不可用,要么用起来不方便,所以呢,很多时候我们是会基于这样的原则来混合使用 QML 和 C++: QML 构建界面, C++ 实现非界面的业务逻辑和复杂运算. 请给

关于Java中进程和线程的详解

一.进程:是程序的一次动态执行,它对应着从代码加载,执行至执行完毕的一个完整的过程,是一个动态的实体,它有自己的生命 周期.它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而被撤消.反映了一个程序在 一定的数据 集上运行的全部动态过程.通过进程控制块(PCB)唯一的标识某个进程.同时进程占据着相应的资源(例如包 括cpu的使用 ,轮转时间以及一些其它设备的权限).是系统进行资源分配和调度的一个独立单位. 程序和进程之间的主要区别在于: 状态         是否具有资源