詳解 Qt 線程間共享數(shù)據(jù)
Qt 線程間共享數(shù)據(jù)是本文介紹的內(nèi)容,多的不說(shuō),先來(lái)啃內(nèi)容。Qt線程間共享數(shù)據(jù)主要有兩種方式:
使用共享內(nèi)存。即使用一個(gè)兩個(gè)線程都能夠共享的變量(如全局變量),這樣兩個(gè)線程都能夠訪問(wèn)和修改該變量,從而達(dá)到共享數(shù)據(jù)的目的;
使用singal/slot機(jī)制,把數(shù)據(jù)從一個(gè)線程傳遞到另外一個(gè)線程。
***種辦法在各個(gè)編程語(yǔ)言都使用普遍,而第二種方式倒是QT的特有方式,下面主要學(xué)習(xí)一下這種方式:
在線程之間傳遞signal與在一個(gè)線程內(nèi)傳遞signal是不一樣的。在一個(gè)線程內(nèi)傳遞signal時(shí),emit語(yǔ)句會(huì)直接調(diào)用所有連接的slot并等待到所有slot被處理完;在線程之間傳遞signal時(shí),slot會(huì)被放到隊(duì)列中(queue),而emit這個(gè)signal后會(huì)馬上返回;默認(rèn)情況,線程之間使用queue機(jī)制,而線程內(nèi)使用direct機(jī)制,但在connect中可以改變這些默認(rèn)的機(jī)制。
- view plaincopy to clipboardprint?
- //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);
- //啟動(dòng)線程
- TextDevice device;
- TextThread foo("foo"), bar("bar");
- //把兩個(gè)線程使用signal/slot連接起來(lái)
- QObject::connect(&foo, SIGNAL(writeText(const QString&)), &device, SLOT(write(const QString&)));
- QObject::connect(&bar, SIGNAL(writeText(const QString&)), &device, SLOT(write(const QString&)));
- //啟動(dòng)線程
- foo.start();
- bar.start();
- device.start();
- QMessageBox::information(0, "Threading", "Close me to stop.");
- //停止線程
- foo.stop();
- bar.stop();
- device.stop();
- //等待線程結(jié)束
- device.wait();
- foo.wait();
- bar.wait();
- return 0;
- }
- //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);
- //啟動(dòng)線程
- TextDevice device;
- TextThread foo("foo"), bar("bar");
- //把兩個(gè)線程使用signal/slot連接起來(lái)
- QObject::connect(&foo, SIGNAL(writeText(const QString&)), &device, SLOT(write(const QString&)));
- QObject::connect(&bar, SIGNAL(writeText(const QString&)), &device, SLOT(write(const QString&)));
- //啟動(dòng)線程
- foo.start();
- bar.start();
- device.start();
- QMessageBox::information(0, "Threading", "Close me to stop.");
- //停止線程
- foo.stop();
- bar.stop();
- device.stop();
- //等待線程結(jié)束
- device.wait();
- foo.wait();
- bar.wait();
- return 0;
- }
#p#
上面例子代碼可以看出兩個(gè)線程之間傳送了類型為QString的信息。像QString等這些QT本身定義的類型,直接傳送即可。但如果是自己定義的類型如果想使用signal/slot來(lái)傳遞的話,則沒(méi)有這么簡(jiǎn)單。直接使用的話,會(huì)產(chǎn)生下面這種錯(cuò)誤:
- QObject::connect: Cannot queue arguments of type 'TextAndNumber' (Make sure 'TextAndNumber' is registed using qRegisterMetaType().)
原因:當(dāng)一個(gè)signal被放到隊(duì)列中(queued)時(shí),它的參數(shù)(arguments)也會(huì)被一起一起放到隊(duì)列中(queued起來(lái)),這就意味著參數(shù)在被傳送到slot之前需要被拷貝、存儲(chǔ)在隊(duì)列中(queue)中;為了能夠在隊(duì)列中存儲(chǔ)這些參數(shù)(argument),Qt需要去construct、destruct、copy這些對(duì)象,而為了讓Qt知道怎樣去作這些事情,參數(shù)的類型需要使用qRegisterMetaType來(lái)注冊(cè)(如錯(cuò)誤提示中的說(shuō)明)
步驟:(以自定義TextAndNumber類型為例)
自定一種類型,在這個(gè)類型的頂部包含:#include <QMetaType>
在類型定義完成后,加入聲明:Q_DECLARE_METATYPE(TextAndNumber);
在main()函數(shù)中注冊(cè)這種類型:qRegisterMetaType<TextAndNumber>("TextAndNumber");
如果還希望使用這種類型的引用,可同樣要注冊(cè):qRegisterMetaType<TextAndNumber>("TextAndNumber&");
- view plaincopy to clipboardprint?
- //TextAndNumber.h
- #ifndef TEXTANDNUMBER_H
- #define TEXTANDNUMBER_H
- #include <QMetaType>
- //必須包含QMetaType,否則會(huì)出現(xiàn)下面錯(cuò)誤:
- //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;
- }
小結(jié):詳解 Qt 線程間共享數(shù)據(jù)的內(nèi)容介紹完了,希望本文對(duì)你有所幫助!