Qt线程间共享数据主要有两种方式:

  • 使用共享内存。即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的;
  • 使用singal/slot机制,把数据从一个线程传递到另外一个线程。

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

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

  1. //TextDevice.h
  2. #ifndef TEXTDEVICE_H
  3. #define TEXTDEVICE_H
  4. #include <QThread>
  5. #include <QString>
  6. #include <QMutex>
  7. class TextDevice : public QThread {
  8. Q_OBJECT
  9. public:
  10. TextDevice();
  11. void run();
  12. void stop();
  13. public slots:
  14. void write(const QString& text);
  15. private:
  16. int m_count;
  17. QMutex m_mutex;
  18. };
  19. #endif // TEXTDEVICE_H
  20. //TextDevice.cpp
  21. #include <QMutexLocker>
  22. #include <QDebug>
  23. #include <QString>
  24. #include "TextDevice.h"
  25. TextDevice::TextDevice() {
  26. m_count = 0;
  27. }
  28. void TextDevice::run() {
  29. exec();
  30. }
  31. void TextDevice::stop() {
  32. quit();
  33. }
  34. void TextDevice::write(const QString& text) {
  35. QMutexLocker locker(&m_mutex);
  36. qDebug() << QString("Call %1: %2").arg(m_count++).arg(text);
  37. }
  38. //TextThread.h
  39. #ifndef TEXTTHREAD_H
  40. #define TEXTTHREAD_H
  41. #include <QThread>
  42. #include <QString>
  43. class TextThread : public QThread {
  44. Q_OBJECT
  45. public:
  46. TextThread(const QString& text);
  47. void run();
  48. void stop();
  49. signals:
  50. void writeText(const QString&);
  51. private:
  52. QString m_text;
  53. bool m_stop;
  54. };
  55. #endif // TEXTTHREAD_H
  56. //TextThread.cpp
  57. #include "TextThread.h"
  58. TextThread::TextThread(const QString& text) : QThread() {
  59. m_text = text;
  60. m_stop = false;
  61. }
  62. void TextThread::stop() {
  63. m_stop = true;
  64. }
  65. void TextThread::run() {
  66. while(!m_stop) {
  67. emit writeText(m_text);
  68. sleep(1);
  69. }
  70. }
  71. //main.cpp
  72. #include <QApplication>
  73. #include <QMessageBox>
  74. #include "TextDevice.h"
  75. #include "TextThread.h"
  76. int main(int argc, char** argv) {
  77. QApplication app(argc, argv);
  78. //启动线程
  79. TextDevice device;
  80. TextThread foo("foo"), bar("bar");
  81. //把两个线程使用signal/slot连接起来
  82. QObject::connect(&foo, SIGNAL(writeText(const QString&)), &device, SLOT(write(const QString&)));
  83. QObject::connect(&bar, SIGNAL(writeText(const QString&)), &device, SLOT(write(const QString&)));
  84. //启动线程
  85. foo.start();
  86. bar.start();
  87. device.start();
  88. QMessageBox::information(0, "Threading", "Close me to stop.");
  89. //停止线程
  90. foo.stop();
  91. bar.stop();
  92. device.stop();
  93. //等待线程结束
  94. device.wait();
  95. foo.wait();
  96. bar.wait();
  97. return 0;
  98. }

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

http://blog.csdn.net/swingline/article/details/5635288

Qt学习:线程间共享数据(使用信号槽传递数据,必须提前使用qRegisterMetaType来注册参数的类型)的更多相关文章

  1. [转]QT子线程与主线程的信号槽通信-亲测可用!

    近用QT做一个服务器,众所周知,QT的主线程必须保持畅通,才能刷新UI.所以,网络通信端采用新开线程的方式.在涉及到使用子线程更新Ui上的控件时遇到了点儿麻烦.网上提供了很多同一线程不同类间采用信号槽 ...

  2. Qt 学习之路:深入 Qt5 信号槽新语法

    在前面的章节(信号槽和自定义信号槽)中,我们详细介绍了有关 Qt 5 的信号槽新语法.由于这次改动很大,许多以前看起来不是问题的问题接踵而来,因此,我们用单独的一章重新介绍一些 Qt 5 的信号槽新语 ...

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

    使用共享内存.即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的. Qt 线程间共享数据是本文介绍的内容,多的不说,先来啃内容.Qt线程间共享 ...

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

    使用共享内存.即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的. Qt 线程间共享数据是本文介绍的内容,多的不说,先来啃内容.Qt线程间共享 ...

  5. Disruptor 线程间共享数据无需竞争

    队列的作用是缓冲 缓冲到 队列的空间里.. 线程间共享数据无需竞争 原文 地址  作者  Trisha   译者:李同杰 LMAX Disruptor 是一个开源的并发框架,并获得2011 Duke’ ...

  6. Qt 学习之路 2(14):对话框数据传递

    Home / Qt 学习之路 2 / Qt 学习之路 2(14):对话框数据传递 Qt 学习之路 2(14):对话框数据传递  豆子  2012年9月15日  Qt 学习之路 2  53条评论 对话框 ...

  7. ThreadLocal实现session中用户信息 的线程间共享(精)

    ThreadLocal并不难理解,我总结的最简单的理解就是: ThreadLocal像其它变量一样(局部.全局.静态)也是一种变量类型,只是他是线程变量,更直白的说他是一种变量作用域,即他的作用域是当 ...

  8. ThreadLocal实现session中用户信息 的线程间共享

    转载自:http://blog.sina.com.cn/s/blog_4b5bc01101013gok.html ThreadLocal并不难理解,我总结的最简单的理解就是: ThreadLocal像 ...

  9. Java并发基础09. 多个线程间共享数据问题

    先看一个多线程间共享数据的问题: 设计四个线程,其中两个线程每次对data增加1,另外两个线程每次对data减少1. 从问题来看,很明显涉及到了线程间通数据的共享,四个线程共享一个 data,共同操作 ...

随机推荐

  1. 【转】context和getApplicationContext()介绍

    在android中常常会遇到与context有关的内容,大多都是作为参数在传递,但是它的作用究竟是什么呢 先说它的用法,举个例子 在语句 AlertDialog.Builder builder = n ...

  2. JS 深拷贝

    使用递归进行深拷贝 http://lingyu.wang/2014/03/20/js-interview-1/ Object.prototype.deepClone = function() { va ...

  3. Word2007中如何插入参考文献

    很多国内的期刊杂志都只能使用word模板,导致插入参考文献成了件麻烦事,这时特别怀念Latex的便捷.于是找到一篇介绍word2007里插入参考文献的好方法,就是利用尾注的方法使文章的参考文献标号可以 ...

  4. Protel99Se使用方法详解

    Protel99SE是应用于Windows9X/2000/NT操作系统下的EDA设计软件,采用设计库管理模式,可以进行联网设计,具有很强的数据交换能力和开放性及3D模拟功能,是一个32位的设计软件,可 ...

  5. rsync、ssh备份

    Linux系统需求 为了实现这个备份程序,需要准备一个外部驱动器.您可以将备份写到一个外部USB磁盘,但这样做效率不高.因此,我假设您将备份写到位于网络某处的服务器中.这台服务器要为带有SSH和rsy ...

  6. MFC消息截获之pretranslatemessage

    前几天,查了一个batch的问题,问题大致是这样,父窗口消息一个鼠标消息,弹出一个模态框,CPU负荷就飚升到100%(双核就是50%),非常怪异,用windbg,分析哪个线程占用CPU,定位到鼠标响应 ...

  7. Windows Azure 网站上的 WordPress 3.8

     编辑人员注释:本文章由 Windows Azure 网站团队的项目经理 Sunitha Muthukrishna 和 Windows Azure 网站开发人员体验合作伙伴共同撰写. WordPr ...

  8. A2W和W2A :很好的多字节和宽字节字符串的转换宏

    以前看<Window核心编程>,感觉多字节和宽字节之间还比较麻烦的,至少MultiByteToWideChar函数和WideCharToMultiByte函数有足够多的参数的意义让我们去理 ...

  9. c++的正整数高精度加减乘除

    数值计算之高精度加减乘除 一.      高精度正整数的高精度计算 1.加法 2.减法 减法和加法的最大区别在于:减法是从高位开始相减,而加法是从低位开始相加 3.乘法:用高精度加法实现 l 乘法的主 ...

  10. 使用jetty和mongodb实现简易网盘接口

    依赖库: 1,jetty(提供http方式接口) 2,mongodb的java驱动(访问mongodb存取文件) 3,thumbnailator包,进行缩略图生成 4,commons-fileuplo ...