您的位置:首页 > 编程语言 > Qt开发

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

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

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: