使用共享内存。即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的。
Qt 线程间共享数据是本文介绍的内容,多的不说,先来啃内容。Qt线程间共享数据主要有两种方式:
使用共享内存。即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的;
使用singal/slot机制,把数据从一个线程传递到另外一个线程。
***种办法在各个编程语言都使用普遍,而第二种方式倒是QT的特有方式,下面主要学习一下这种方式:
在线程之间传递signal与在一个线程内传递signal是不一样的。在一个线程内传递signal时,emit语句会直接调用所有连接的slot并等待到所有slot被处理完;在线程之间传递signal时,slot会被放到队列中(queue),而emit这个signal后会马上返回;默认情况,线程之间使用queue机制,而线程内使用direct机制,但在connect中可以改变这些默认的机制。
- viewplaincopytoclipboardprint?
- //TextDevice.h
- #ifndefTEXTDEVICE_H
- #defineTEXTDEVICE_H
- #include<QThread>
- #include<QString>
- #include<QMutex>
- classTextDevice:publicQThread{
- Q_OBJECT
- public:
- TextDevice();
- voidrun();
- voidstop();
- publicslots:
- voidwrite(constQString&text);
- private:
- intm_count;
- QMutexm_mutex;
- };
- #endif//TEXTDEVICE_H
- //TextDevice.cpp
- #include<QMutexLocker>
- #include<QDebug>
- #include<QString>
- #include"TextDevice.h"
- TextDevice::TextDevice(){
- m_count=0;
- }
- voidTextDevice::run(){
- exec();
- }
- voidTextDevice::stop(){
- quit();
- }
- voidTextDevice::write(constQString&text){
- QMutexLockerlocker(&m_mutex);
- qDebug()<<QString("Call%1:%2").arg(m_count++).arg(text);
- }
- //TextThread.h
- #ifndefTEXTTHREAD_H
- #defineTEXTTHREAD_H
- #include<QThread>
- #include<QString>
- classTextThread:publicQThread{
- Q_OBJECT
- public:
- TextThread(constQString&text);
- voidrun();
- voidstop();
- signals:
- voidwriteText(constQString&);
- private:
- QStringm_text;
- boolm_stop;
- };
- #endif//TEXTTHREAD_H
- //TextThread.cpp
- #include"TextThread.h"
- TextThread::TextThread(constQString&text):QThread(){
- m_text=text;
- m_stop=false;
- }
- voidTextThread::stop(){
- m_stop=true;
- }
- voidTextThread::run(){
- while(!m_stop){
- emitwriteText(m_text);
- sleep(1);
- }
- }
- //main.cpp
- #include<QApplication>
- #include<QMessageBox>
- #include"TextDevice.h"
- #include"TextThread.h"
- intmain(intargc,char**argv){
- QApplicationapp(argc,argv);
- //启动线程
- TextDevicedevice;
- TextThreadfoo("foo"),bar("bar");
- //把两个线程使用signal/slot连接起来
- QObject::connect(&foo,SIGNAL(writeText(constQString&)),&device,SLOT(write(constQString&)));
- QObject::connect(&bar,SIGNAL(writeText(constQString&)),&device,SLOT(write(constQString&)));
- //启动线程
- foo.start();
- bar.start();
- device.start();
- QMessageBox::information(0,"Threading","Closemetostop.");
- //停止线程
- foo.stop();
- bar.stop();
- device.stop();
- //等待线程结束
- device.wait();
- foo.wait();
- bar.wait();
- return0;
- }
- //TextDevice.h
- #ifndefTEXTDEVICE_H
- #defineTEXTDEVICE_H
- #include<QThread>
- #include<QString>
- #include<QMutex>
- classTextDevice:publicQThread{
- Q_OBJECT
- public:
- TextDevice();
- voidrun();
- voidstop();
- publicslots:
- voidwrite(constQString&text);
- private:
- intm_count;
- QMutexm_mutex;
- };
- #endif//TEXTDEVICE_H
- //TextDevice.cpp
- #include<QMutexLocker>
- #include<QDebug>
- #include<QString>
- #include"TextDevice.h"
- TextDevice::TextDevice(){
- m_count=0;
- }
- voidTextDevice::run(){
- exec();
- }
- voidTextDevice::stop(){
- quit();
- }
- voidTextDevice::write(constQString&text){
- QMutexLockerlocker(&m_mutex);
- qDebug()<<QString("Call%1:%2").arg(m_count++).arg(text);
- }
- //TextThread.h
- #ifndefTEXTTHREAD_H
- #defineTEXTTHREAD_H
- #include<QThread>
- #include<QString>
- classTextThread:publicQThread{
- Q_OBJECT
- public:
- TextThread(constQString&text);
- voidrun();
- voidstop();
- signals:
- voidwriteText(constQString&);
- private:
- QStringm_text;
- boolm_stop;
- };
- #endif//TEXTTHREAD_H
- //TextThread.cpp
- #include"TextThread.h"
- TextThread::TextThread(constQString&text):QThread(){
- m_text=text;
- m_stop=false;
- }
- voidTextThread::stop(){
- m_stop=true;
- }
- voidTextThread::run(){
- while(!m_stop){
- emitwriteText(m_text);
- sleep(1);
- }
- }
- //main.cpp
- #include<QApplication>
- #include<QMessageBox>
- #include"TextDevice.h"
- #include"TextThread.h"
- intmain(intargc,char**argv){
- QApplicationapp(argc,argv);
- //启动线程
- TextDevicedevice;
- TextThreadfoo("foo"),bar("bar");
- //把两个线程使用signal/slot连接起来
- QObject::connect(&foo,SIGNAL(writeText(constQString&)),&device,SLOT(write(constQString&)));
- QObject::connect(&bar,SIGNAL(writeText(constQString&)),&device,SLOT(write(constQString&)));
- //启动线程
- foo.start();
- bar.start();
- device.start();
- QMessageBox::information(0,"Threading","Closemetostop.");
- //停止线程
- foo.stop();
- bar.stop();
- device.stop();
- //等待线程结束
- device.wait();
- foo.wait();
- bar.wait();
- return0;
- }
#p#
上面例子代码可以看出两个线程之间传送了类型为QString的信息。像QString等这些QT本身定义的类型,直接传送即可。但如果是自己定义的类型如果想使用signal/slot来传递的话,则没有这么简单。直接使用的话,会产生下面这种错误:
- 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&");
- viewplaincopytoclipboardprint?
- //TextAndNumber.h
- #ifndefTEXTANDNUMBER_H
- #defineTEXTANDNUMBER_H
- #include<QMetaType>
- //必须包含QMetaType,否则会出现下面错误:
- //error:expectedconstructor,destructor,ortypeconversionbefore‘;’token
- #include<QString>
- classTextAndNumber{
- public:
- TextAndNumber();
- TextAndNumber(int,QString);
- intcount();
- QStringtext();
- private:
- intm_count;
- QStringm_text;
- };
- Q_DECLARE_METATYPE(TextAndNumber);
- #endif//TEXTANDNUMBER_H
- //TextAndNumber.cpp
- #include"TextAndNumber.h"
- TextAndNumber::TextAndNumber(){
- }
- TextAndNumber::TextAndNumber(intcount,QStringtext){
- m_count=count;
- m_text=text;
- }
- intTextAndNumber::count(){
- returnm_count;
- }
- QStringTextAndNumber::text(){
- returnm_text;
- }
- //TextDevice.h
- #ifndefTEXTDEVICE_H
- #defineTEXTDEVICE_H
- #include<QThread>
- #include<QDebug>
- #include<QString>
- #include"TextAndNumber.h"
- classTextDevice:publicQThread{
- Q_OBJECT
- public:
- TextDevice();
- voidrun();
- voidstop();
- publicslots:
- voidwrite(TextAndNumber&tran);
- private:
- intm_count;
- };
- #endif//TEXTDEVICE_H
- //TextDevice.cpp
- #include"TextDevice.h"
- TextDevice::TextDevice():QThread(){
- m_count=0;
- }
- voidTextDevice::run(){
- exec();
- }
- voidTextDevice::stop(){
- quit();
- }
- voidTextDevice::write(TextAndNumber&tran){
- qDebug()<<QString("Call%1(%3):%2").arg(m_count++).arg(tran.text()).arg(tran.count());
- }
- //TextThread.h
- #ifndefTEXTTHREAD_H
- #defineTEXTTHREAD_H
- #include<QThread>
- #include<QString>
- #include"TextAndNumber.h"
- classTextThread:publicQThread{
- Q_OBJECT
- public:
- TextThread(constQString&text);
- voidrun();
- voidstop();
- signals:
- voidwriteText(TextAndNumber&tran);
- private:
- QStringm_text;
- intm_count;
- boolm_stop;
- };
- #endif//TEXTTHREAD_H
- //TextThread.cpp
- #include"TextThread.h"
- TextThread::TextThread(constQString&text):QThread(){
- m_text=text;
- m_stop=false;
- m_count=0;
- }
- voidTextThread::run(){
- while(!m_stop){
- TextAndNumbertn(m_count++,m_text);
- emitwriteText(tn);
- sleep(1);
- }
- }
- voidTextThread::stop(){
- m_stop=true;
- }
- //main.cpp
- #include<QApplication>
- #include<QMessageBox>
- #include"TextThread.h"
- #include"TextDevice.h"
- #include"TextAndNumber.h"
- intmain(intargc,char*argv[])
- {
- QApplicationapp(argc,argv);
- qRegisterMetaType<TextAndNumber>("TextAndNumber");
- qRegisterMetaType<TextAndNumber>("TextAndNumber&");
- TextDevicedevice;
- TextThreadfoo("foo"),bar("bar");
- QObject::connect(&foo,SIGNAL(writeText(TextAndNumber&)),&device,SLOT(write(TextAndNumber&)));
- QObject::connect(&bar,SIGNAL(writeText(TextAndNumber&)),&device,SLOT(write(TextAndNumber&)));
- device.start();
- foo.start();
- bar.start();
- QMessageBox::information(0,"Threading","Clickmetoclose");
- foo.stop();
- bar.stop();
- device.stop();
- foo.wait();
- bar.wait();
- device.wait();
- qDebug()<<"Applicationend.";
- return0;
- }
小结:详解 Qt 线程间共享数据的内容介绍完了,希望本文对你有所帮助!
知优网 » 详解 Qt 线程间共享数据(qt多线程共享数据)