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

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

详解 Qt 线程间共享数据(qt多线程共享数据)  线程 共享 数据 第1张

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

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

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

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

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

#p#

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

  1. QObject::connect:Cannotqueueargumentsoftype'TextAndNumber'(Makesure'TextAndNumber'isregistedusingqRegisterMetaType().)

原因:当一个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. viewplaincopytoclipboardprint?
  2. //TextAndNumber.h
  3. #ifndefTEXTANDNUMBER_H
  4. #defineTEXTANDNUMBER_H
  5. #include<QMetaType>
  6. //必须包含QMetaType,否则会出现下面错误:
  7. //error:expectedconstructor,destructor,ortypeconversionbefore‘;’token
  8. #include<QString>
  9. classTextAndNumber{
  10. public:
  11. TextAndNumber();
  12. TextAndNumber(int,QString);
  13. intcount();
  14. QStringtext();
  15. private:
  16. intm_count;
  17. QStringm_text;
  18. };
  19. Q_DECLARE_METATYPE(TextAndNumber);
  20. #endif//TEXTANDNUMBER_H
  21. //TextAndNumber.cpp
  22. #include"TextAndNumber.h"
  23. TextAndNumber::TextAndNumber(){
  24. }
  25. TextAndNumber::TextAndNumber(intcount,QStringtext){
  26. m_count=count;
  27. m_text=text;
  28. }
  29. intTextAndNumber::count(){
  30. returnm_count;
  31. }
  32. QStringTextAndNumber::text(){
  33. returnm_text;
  34. }
  35. //TextDevice.h
  36. #ifndefTEXTDEVICE_H
  37. #defineTEXTDEVICE_H
  38. #include<QThread>
  39. #include<QDebug>
  40. #include<QString>
  41. #include"TextAndNumber.h"
  42. classTextDevice:publicQThread{
  43. Q_OBJECT
  44. public:
  45. TextDevice();
  46. voidrun();
  47. voidstop();
  48. publicslots:
  49. voidwrite(TextAndNumber&tran);
  50. private:
  51. intm_count;
  52. };
  53. #endif//TEXTDEVICE_H
  54. //TextDevice.cpp
  55. #include"TextDevice.h"
  56. TextDevice::TextDevice():QThread(){
  57. m_count=0;
  58. }
  59. voidTextDevice::run(){
  60. exec();
  61. }
  62. voidTextDevice::stop(){
  63. quit();
  64. }
  65. voidTextDevice::write(TextAndNumber&tran){
  66. qDebug()<<QString("Call%1(%3):%2").arg(m_count++).arg(tran.text()).arg(tran.count());
  67. }
  68. //TextThread.h
  69. #ifndefTEXTTHREAD_H
  70. #defineTEXTTHREAD_H
  71. #include<QThread>
  72. #include<QString>
  73. #include"TextAndNumber.h"
  74. classTextThread:publicQThread{
  75. Q_OBJECT
  76. public:
  77. TextThread(constQString&text);
  78. voidrun();
  79. voidstop();
  80. signals:
  81. voidwriteText(TextAndNumber&tran);
  82. private:
  83. QStringm_text;
  84. intm_count;
  85. boolm_stop;
  86. };
  87. #endif//TEXTTHREAD_H
  88. //TextThread.cpp
  89. #include"TextThread.h"
  90. TextThread::TextThread(constQString&text):QThread(){
  91. m_text=text;
  92. m_stop=false;
  93. m_count=0;
  94. }
  95. voidTextThread::run(){
  96. while(!m_stop){
  97. TextAndNumbertn(m_count++,m_text);
  98. emitwriteText(tn);
  99. sleep(1);
  100. }
  101. }
  102. voidTextThread::stop(){
  103. m_stop=true;
  104. }
  105. //main.cpp
  106. #include<QApplication>
  107. #include<QMessageBox>
  108. #include"TextThread.h"
  109. #include"TextDevice.h"
  110. #include"TextAndNumber.h"
  111. intmain(intargc,char*argv[])
  112. {
  113. QApplicationapp(argc,argv);
  114. qRegisterMetaType<TextAndNumber>("TextAndNumber");
  115. qRegisterMetaType<TextAndNumber>("TextAndNumber&");
  116. TextDevicedevice;
  117. TextThreadfoo("foo"),bar("bar");
  118. QObject::connect(&foo,SIGNAL(writeText(TextAndNumber&)),&device,SLOT(write(TextAndNumber&)));
  119. QObject::connect(&bar,SIGNAL(writeText(TextAndNumber&)),&device,SLOT(write(TextAndNumber&)));
  120. device.start();
  121. foo.start();
  122. bar.start();
  123. QMessageBox::information(0,"Threading","Clickmetoclose");
  124. foo.stop();
  125. bar.stop();
  126. device.stop();
  127. foo.wait();
  128. bar.wait();
  129. device.wait();
  130. qDebug()<<"Applicationend.";
  131. return0;
  132. }

小结:详解 Qt 线程共享数据的内容介绍完了,希望本文对你有所帮助!

转载请说明出处
知优网 » 详解 Qt 线程间共享数据(qt多线程共享数据)

发表评论

您需要后才能发表评论