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

55 篇文章 1 订阅

demo下载地址为:https://download.csdn.net/download/flowerspring/11022469

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

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值