Qt多线程间传递变量方法总结

参考:http://www.cnblogs.com/bingcaihuang/archive/2011/07/14/2106885.html

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

第一种办法在各个编程语言都使用普遍,而第二种方式倒是QT的特有方式,下面主要学习一下这种方式:在线程之间传递signal与在一个线程内传递signal是不一样的。在一个线程内传递signal时,emit语句会直接调用所有连接的slot并等待到所有slot被处理完;在线程之间传递signal时,slot会被放到队列中(queue),而emit这个signal后会马上返回;默认情况,线程之间使用queue机制,而线程内使用direct机制,但在connect中可以改变这些默认的机制。

TextDevice.h


 
 
  1. #ifndef TEXTDEVICE_H
  2. #define TEXTDEVICE_H
  3. #include <QThread>
  4. #include <QString>
  5. #include <QMutex>
  6. class TextDevice : public QThread {
  7. Q_OBJECT
  8. public:
  9. TextDevice();
  10. void run();
  11. void stop();
  12. public slots:
  13. void write(const QString& text);
  14. private:
  15. int m_count;
  16. QMutex m_mutex;
  17. };
  18. #endif // TEXTDEVICE_H
TextDevice.cpp

 
 
  1. include <QMutexLocker>
  2. #include <QDebug>
  3. #include <QString>
  4. #include "TextDevice.h"
  5. TextDevice::TextDevice() {
  6. m_count = 0;
  7. }
  8. void TextDevice::run() {
  9. exec();
  10. }
  11. void TextDevice::stop() {
  12. quit();
  13. }
  14. void TextDevice::write( const QString& text) {
  15. QMutexLocker locker(&m_mutex);
  16. qDebug() << QString( "Call %1: %2").arg(m_count++).arg(text);}
TextThread.h 


 
 
  1. #ifndef TEXTTHREAD_H
  2. #define TEXTTHREAD_H
  3. #include <QThread>
  4. #include <QString>
  5. class TextThread : public QThread {
  6. Q_OBJECT
  7. public:
  8. TextThread( const QString& text);
  9. void run();
  10. void stop();
  11. signals:
  12. void writeText(const QString&);
  13. private:
  14. QString m_text;
  15. bool m_stop;
  16. };
  17. #endif // TEXTTHREAD_H
TextThread.cpp 

 
 
  1. #include "TextThread.h"
  2. TextThread::TextThread( const QString& text) : QThread() {
  3. m_text = text;
  4. m_stop = false;
  5. }
  6. void TextThread::stop() {
  7. m_stop = true;
  8. }
  9. void TextThread::run() {
  10. while(!m_stop) {
  11. emit writeText(m_text);
  12. sleep( 1);
  13. }
  14. }
main.cpp 


 
 
  1. #include <QApplication>
  2. #include <QMessageBox>
  3. #include "TextDevice.h"
  4. #include "TextThread.h"
  5. int main(int argc, char** argv) {
  6. QApplication app(argc, argv);
  7. //启动线程
  8. TextDevice device;
  9. TextThread foo("foo"), bar("bar");
  10. //把两个线程使用signal/slot连接起来
  11. QObject::connect(&foo, SIGNAL(writeText( const QString&)), &device, SLOT(write( const QString&)));
  12. QObject::connect(&bar, SIGNAL(writeText( const QString&)), &device, SLOT(write( const QString&)));
  13. //启动线程
  14. foo.start();
  15. bar.start();
  16. device.start();
  17. QMessageBox::information( 0, "Threading", "Close me to stop.");
  18. //停止线程
  19. foo.stop();
  20. bar.stop();
  21. device.stop();
  22. //等待线程结束
  23. device.wait();
  24. foo.wait();
  25. bar.wait();
  26. return 0;
  27. }

上面例子代码可以看出两个线程之间传送了类型为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&");

TextAndNumber.h


 
 
  1. #ifndef TEXTANDNUMBER_H
  2. #define TEXTANDNUMBER_H
  3. #include <QMetaType>
  4. //必须包含QMetaType,否则会出现下面错误:
  5. //error: expected constructor, destructor, or type conversion before ‘;’ token
  6. #include <QString>
  7. class TextAndNumber {
  8. public:
  9. TextAndNumber();
  10. TextAndNumber( int, QString);
  11. int count();
  12. QString text();
  13. private:
  14. int m_count;
  15. QString m_text;
  16. };
  17. Q_DECLARE_METATYPE(TextAndNumber);
  18. #endif // TEXTANDNUMBER_H
TextAndNumber.cpp


 
 
  1. #include "TextAndNumber.h"
  2. TextAndNumber::TextAndNumber() {
  3. }
  4. TextAndNumber::TextAndNumber( int count, QString text) {
  5. m_count = count;
  6. m_text = text;
  7. }
  8. int TextAndNumber::count() {
  9. return m_count;
  10. }
  11. QString TextAndNumber::text() {
  12. return m_text;
  13. }
TextDevice.h


 
 
  1. #ifndef TEXTDEVICE_H
  2. #define TEXTDEVICE_H
  3. #include <QThread>
  4. #include <QDebug>
  5. #include <QString>
  6. #include "TextAndNumber.h"
  7. class TextDevice : public QThread {
  8. Q_OBJECT
  9. public:
  10. TextDevice();
  11. void run();
  12. void stop();
  13. public slots:
  14. void write(TextAndNumber& tran);
  15. private:
  16. int m_count;
  17. };
  18. #endif // TEXTDEVICE_H
TextDevice.cpp 


 
 
  1. #include "TextDevice.h"
  2. TextDevice::TextDevice() : QThread() {
  3. m_count = 0;
  4. }
  5. void TextDevice::run() {
  6. exec();
  7. }
  8. void TextDevice::stop() {
  9. quit();
  10. }
  11. void TextDevice::write(TextAndNumber& tran) {
  12. qDebug() << QString( "Call %1 (%3): %2").arg(m_count++).arg(tran.text()).arg(tran.count());
  13. }
TextThread.h


 
 
  1. #ifndef TEXTTHREAD_H
  2. #define TEXTTHREAD_H
  3. #include <QThread>
  4. #include <QString>
  5. #include "TextAndNumber.h"
  6. class TextThread : public QThread {
  7. Q_OBJECT
  8. public:
  9. TextThread( const QString& text);
  10. void run();
  11. void stop();
  12. signals:
  13. void writeText(TextAndNumber& tran);
  14. private:
  15. QString m_text;
  16. int m_count;
  17. bool m_stop;
  18. };
  19. #endif // TEXTTHREAD_H
TextThread.cpp


 
 
  1. #include "TextThread.h"
  2. TextThread::TextThread( const QString& text) : QThread() {
  3. m_text = text;
  4. m_stop = false;
  5. m_count = 0;
  6. }
  7. void TextThread::run() {
  8. while(!m_stop) {
  9. TextAndNumber tn(m_count++, m_text);
  10. emit writeText(tn);
  11. sleep( 1);
  12. }
  13. }
  14. void TextThread::stop() {
  15. m_stop = true;
  16. }
main.cpp


 
 
  1. #include <QApplication>
  2. #include <QMessageBox>
  3. #include "TextThread.h"
  4. #include "TextDevice.h"
  5. #include "TextAndNumber.h"
  6. int main(int argc, char *argv[])
  7. {
  8. QApplication app(argc, argv);
  9. qRegisterMetaType<TextAndNumber>( "TextAndNumber");
  10. qRegisterMetaType<TextAndNumber>( "TextAndNumber&");
  11. TextDevice device;
  12. TextThread foo("foo"), bar("bar");
  13. QObject::connect(&foo, SIGNAL(writeText(TextAndNumber&)), &device, SLOT(write(TextAndNumber&)));
  14. QObject::connect(&bar, SIGNAL(writeText(TextAndNumber&)), &device, SLOT(write(TextAndNumber&)));
  15. device.start();
  16. foo.start();
  17. bar.start();
  18. QMessageBox::information( 0, "Threading", "Click me to close");
  19. foo.stop();
  20. bar.stop();
  21. device.stop();
  22. foo.wait();
  23. bar.wait();
  24. device.wait();
  25. qDebug() << "Application end.";
  26. return 0;
  27. }
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值