There are two main ways to share data between Qt threads:
Use shared memory.Even with a variable that both threads can share (such as a global variable), both threads can access and modify the variable to share data. Use the singal/slot mechanism to transfer data from one thread to another.
The first is common in all programming languages, while the second is specific to QT. Here's how to learn about it:
Passing a signal between threads is different from passing a signal within a thread.When a signal is passed within a thread, the emit statement calls all connected slots directly and waits until all slots are processed; when a signal is passed between threads, the slot is placed in a queue, and the emit signal is returned immediately; by default, the queue mechanism is used between threads, and the director is used within threadsMechanisms, but these default mechanisms can be changed in 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); //Start Thread TextDevice device; TextThread foo("foo"), bar("bar"); //Connect two threads using 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&))); //Start Thread foo.start(); bar.start(); device.start(); QMessageBox::information(0, "Threading", "Close me to stop."); //Stop Thread foo.stop(); bar.stop(); device.stop(); //Waiting for thread to end device.wait(); foo.wait(); bar.wait(); return 0; }
The example code above shows that information of type QString is passed between two threads.Types defined by these QT s themselves, such as QString, can be directly transferred.But if it's your own type and you want to pass it using signal/slot, it's not that simple.When used directly, the following errors occur:
QObject::connect: Cannot queue arguments of type 'TextAndNumber' (Make sure 'TextAndNumber' is registed using qRegisterMetaType().)
Reason: When a signal is queued, its arguments are also queued together, which means that the parameters need to be copied and stored in the queue before being transmitted to the slot; in order to be able to store these arguments in the queue, Qt needs toTo construct, destruct, copy these objects, and to let Qt know how to do these things, the type of parameter needs to be registered using qRegisterMetaType (as described in the error prompt)
Step: (Take the custom TextAndNumber type as an example) Customize a type that contains at the top of this type: #include <QMetaType> After the type definition is complete, add a declaration: Q_DECLARE_METATYPE(TextAndNumber); Register this type in the main() function: qRegisterMetaType <TextAndNumber> ("TextAndNumber"); If you also want to use this type of reference, you can also register: qRegisterMetaType <TextAndNumber> ("TextAndNumber &");
[cpp] view plaincopy
//TextAndNumber.h #ifndef TEXTANDNUMBER_H #define TEXTANDNUMBER_H #include <QMetaType> //QMetaType must be included, otherwise the following error will occur: //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; }