Qt学习:线程间共享数据

转载 2013年12月05日 18:34:56

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

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

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

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

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

 

上面例子代码可以看出两个线程之间传送了类型为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.   
  21. //TextAndNumber.cpp  
  22. #include "TextAndNumber.h"  
  23. TextAndNumber::TextAndNumber() {  
  24. }  
  25. TextAndNumber::TextAndNumber(int count, QString text) {  
  26.     m_count = count;  
  27.     m_text = text;  
  28. }  
  29. int TextAndNumber::count() {  
  30.     return m_count;  
  31. }  
  32. QString TextAndNumber::text() {  
  33.     return m_text;  
  34. }  
  35.   
  36. //TextDevice.h  
  37. #ifndef TEXTDEVICE_H  
  38. #define TEXTDEVICE_H  
  39. #include <QThread>  
  40. #include <QDebug>  
  41. #include <QString>  
  42. #include "TextAndNumber.h"  
  43. class TextDevice : public QThread {  
  44.     Q_OBJECT  
  45. public:  
  46.     TextDevice();  
  47.     void run();  
  48.     void stop();  
  49. public slots:  
  50.     void write(TextAndNumber& tran);  
  51. private:  
  52.     int m_count;  
  53. };  
  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.   
  132.     foo.stop();  
  133.     bar.stop();  
  134.     device.stop();  
  135.     foo.wait();  
  136.     bar.wait();  
  137.     device.wait();  
  138.     qDebug() << "Application end.";  
  139.     return 0;  
  140. }  

 

深度学习之标注工具【Qt版】

前几天,用Qt写了个图像标注工具,最近电脑崩了,然后界面化的东西发不了了,待我将电脑 环境,编译好再发。这里先提供Qt源代码。测试环境:win10 64x QtCreator5.7.0, ope...
  • Charel_CHEN
  • Charel_CHEN
  • 2017年05月28日 15:56
  • 920

Qt中绘制蚂蚁线

提要如果有用过PS的选区工具应该就会知道蚂蚁线是什么东西了,就是用来表示选区的一种虚线,关键还是要动态的!Qt 中自带的一个例子就有各种描边的演示,但是最终达到的效果只能是一个静态的描边,根本不够炫酷...
  • qp120291570
  • qp120291570
  • 2014年12月03日 17:14
  • 2460

永久解决vs2013+qt+opencv中代码下面很多红色波浪线

解决办法:项目->属性->vc++目录->包含目录->添加qt的include路径(我的是E:\qt\install_qt-opensource-windows-x86-msvc2013_64_ope...
  • IT_job
  • IT_job
  • 2017年12月07日 09:20
  • 182

Qt学习笔记:画一条带箭头的线

QPainterPathQPainterPath其实是一个容器,他可以包含一个或者多个不同的绘画步骤,通过这些步骤组成较为复杂的图案,然后使用QPainter.drawPath()将这些图案一次性画出...
  • founderznd
  • founderznd
  • 2016年06月14日 00:15
  • 3779

机器学习实践系列之11 - OpenCV实战车道线检测

ADAS 在经过资本的一轮热炒之后已经不新鲜了,Mobile Eye的技术积累和效果也让很多童鞋叹为观止,然后奋起直指!        初学者为代表的童鞋,二话不说,上来就是霍夫变换,还是直接用ope...
  • linolzhang
  • linolzhang
  • 2017年02月17日 23:01
  • 1492

我的K线图学习之路(iOS)

一、什么是K线图 1、K线图的定义:      K线(Candlestick chart)又称“阴阳烛”,是反映价格走势的一种图线,其特色在于一个线段内记录了多项讯息,相当易读易懂且实用有效,广泛用于...
  • qq_17808031
  • qq_17808031
  • 2017年02月27日 11:49
  • 176

ADAS-DL-车道线检测

传统的车道检测方法分两步:(1)特征提取(2)车道几何模型的建立与匹配 深度学习相关数据集: 1)ROMA http://perso.lcpc.fr/tarel.jean-philippe/bdd...
  • u010069760
  • u010069760
  • 2017年11月07日 10:50
  • 679

C++与QT学习路线

1、流输入输出概念 需要掌握cin、cout和fstream流 2、new与delete(配合类理解) 3、inline函数与#define的区别,学会使用inline ...
  • jay19900101
  • jay19900101
  • 2015年04月23日 10:52
  • 833

一个半路出家的10年程序员:谈工作、学习与Qt

 2014-12-16 03:25 ⁄ 工业·编程 ⁄ 共 9620字 ⁄ 字号 小 中 大 ⁄ 评论 8 条     安晓辉,2014年CSDN博文大赛编...
  • sanmaoljh
  • sanmaoljh
  • 2015年11月04日 17:52
  • 3328

Qt学习很好的总结

widget,MainWindow和Dialog的选择使用 2012-11-06 10:39:30 分类: LINUX Qt中的每个类,都有一个对应的同名头文件,其中包...
  • foreverhuylee
  • foreverhuylee
  • 2015年04月19日 21:02
  • 3058
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Qt学习:线程间共享数据
举报原因:
原因补充:

(最多只允许输入30个字)