您的位置:首页 > 编程语言 > Qt开发

Qt学习:线程间共享数据

2013-12-05 18:34 399 查看
Qt线程间共享数据主要有两种方式:

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

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

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

[c-sharp] view
plaincopy

//TextDevice.h

#ifndef TEXTDEVICE_H

#define TEXTDEVICE_H

#include <QThread>

#include <QString>

#include <QMutex>

class TextDevice : public QThread {

Q_OBJECT

public:

TextDevice();

void run();

void stop();

public slots:

void write(const QString& text);

private:

int m_count;

QMutex m_mutex;

};

#endif // TEXTDEVICE_H

//TextDevice.cpp

#include <QMutexLocker>

#include <QDebug>

#include <QString>

#include "TextDevice.h"

TextDevice::TextDevice() {

m_count = 0;

}

void TextDevice::run() {

exec();

}

void TextDevice::stop() {

quit();

}

void TextDevice::write(const QString& text) {

QMutexLocker locker(&m_mutex);

qDebug() << QString("Call %1: %2").arg(m_count++).arg(text);

}

//TextThread.h

#ifndef TEXTTHREAD_H

#define TEXTTHREAD_H

#include <QThread>

#include <QString>

class TextThread : public QThread {

Q_OBJECT

public:

TextThread(const QString& text);

void run();

void stop();

signals:

void writeText(const QString&);

private:

QString m_text;

bool m_stop;

};

#endif // TEXTTHREAD_H

//TextThread.cpp

#include "TextThread.h"

TextThread::TextThread(const QString& text) : QThread() {

m_text = text;

m_stop = false;

}

void TextThread::stop() {

m_stop = true;

}

void TextThread::run() {

while(!m_stop) {

emit writeText(m_text);

sleep(1);

}

}

//main.cpp

#include <QApplication>

#include <QMessageBox>

#include "TextDevice.h"

#include "TextThread.h"

int main(int argc, char** argv) {

QApplication app(argc, argv);

//启动线程

TextDevice device;

TextThread foo("foo"), bar("bar");

//把两个线程使用signal/slot连接起来

QObject::connect(&foo, SIGNAL(writeText(const QString&)), &device, SLOT(write(const QString&)));

QObject::connect(&bar, SIGNAL(writeText(const QString&)), &device, SLOT(write(const QString&)));

//启动线程

foo.start();

bar.start();

device.start();

QMessageBox::information(0, "Threading", "Close me to stop.");

//停止线程

foo.stop();

bar.stop();

device.stop();

//等待线程结束

device.wait();

foo.wait();

bar.wait();

return 0;

}

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

//TextAndNumber.h

#ifndef TEXTANDNUMBER_H

#define TEXTANDNUMBER_H

#include <QMetaType>

//必须包含QMetaType,否则会出现下面错误:

//error: expected constructor, destructor, or type conversion before ‘;’ token

#include <QString>

class TextAndNumber {

public:

TextAndNumber();

TextAndNumber(int, QString);

int count();

QString text();

private:

int m_count;

QString m_text;

};

Q_DECLARE_METATYPE(TextAndNumber);

#endif // TEXTANDNUMBER_H

//TextAndNumber.cpp

#include "TextAndNumber.h"

TextAndNumber::TextAndNumber() {

}

TextAndNumber::TextAndNumber(int count, QString text) {

m_count = count;

m_text = text;

}

int TextAndNumber::count() {

return m_count;

}

QString TextAndNumber::text() {

return m_text;

}

//TextDevice.h

#ifndef TEXTDEVICE_H

#define TEXTDEVICE_H

#include <QThread>

#include <QDebug>

#include <QString>

#include "TextAndNumber.h"

class TextDevice : public QThread {

Q_OBJECT

public:

TextDevice();

void run();

void stop();

public slots:

void write(TextAndNumber& tran);

private:

int m_count;

};

#endif // TEXTDEVICE_H

//TextDevice.cpp

#include "TextDevice.h"

TextDevice::TextDevice() : QThread() {

m_count = 0;

}

void TextDevice::run() {

exec();

}

void TextDevice::stop() {

quit();

}

void TextDevice::write(TextAndNumber& tran) {

qDebug() << QString("Call %1 (%3): %2").arg(m_count++).arg(tran.text()).arg(tran.count());

}

//TextThread.h

#ifndef TEXTTHREAD_H

#define TEXTTHREAD_H

#include <QThread>

#include <QString>

#include "TextAndNumber.h"

class TextThread : public QThread {

Q_OBJECT

public:

TextThread(const QString& text);

void run();

void stop();

signals:

void writeText(TextAndNumber& tran);

private:

QString m_text;

int m_count;

bool m_stop;

};

#endif // TEXTTHREAD_H

//TextThread.cpp

#include "TextThread.h"

TextThread::TextThread(const QString& text) : QThread() {

m_text = text;

m_stop = false;

m_count = 0;

}

void TextThread::run() {

while(!m_stop) {

TextAndNumber tn(m_count++, m_text);

emit writeText(tn);

sleep(1);

}

}

void TextThread::stop() {

m_stop = true;

}

//main.cpp

#include <QApplication>

#include <QMessageBox>

#include "TextThread.h"

#include "TextDevice.h"

#include "TextAndNumber.h"

int main(int argc, char *argv[])

{

QApplication app(argc, argv);

qRegisterMetaType<TextAndNumber>("TextAndNumber");

qRegisterMetaType<TextAndNumber>("TextAndNumber&");

TextDevice device;

TextThread foo("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", "Click me to close");

foo.stop();

bar.stop();

device.stop();

foo.wait();

bar.wait();

device.wait();

qDebug() << "Application end.";

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: