zoukankan      html  css  js  c++  java
  • Qt学习:线程间共享数据(使用信号槽传递数据,必须提前使用qRegisterMetaType来注册参数的类型)

    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&");
    [cpp] view plaincopy
     
    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. }  

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

  • 相关阅读:
    Oracle 10g R2 Transparent Data Encryption 透明数据加密
    Spark之Task原理分析
    一个Spark job的生命历程
    Spark调优秘诀——超详细
    NLP文本相似度(TF-IDF)
    Spark 参数配置的几种方法
    Spark提交应用程序之Spark-Submit分析
    spark_flume_mysql 整合
    Spark Programming Guide《翻译》
    windows下Idea结合maven开发spark和本地调试
  • 原文地址:https://www.cnblogs.com/findumars/p/5133826.html
Copyright © 2011-2022 走看看