QThread
की आंतरिक कार्यप्रणाली अप्रासंगिक हैं: वे ईवेंट लूप कैसे काम करते हैं में कोई भूमिका निभाते हैं। जब आप emit
QObject
में एक सिग्नल जो स्लॉट के ऑब्जेक्ट से भिन्न धागे में रहता है, तो सिग्नल को QMetaCallEvent
के रूप में प्राप्त थ्रेड के ईवेंट कतार में पोस्ट किया जाएगा। प्राप्त करने वाले थ्रेड में चल रहे ईवेंट लूप इस घटना पर कार्य करेंगे और कॉल को उस स्लॉट में निष्पादित करेंगे जो उत्सर्जित सिग्नल से जुड़ा था।
तो, कोई फर्क नहीं पड़ता कि क्या होता है, सिग्नल के माध्यम से जो भी डेटा आप भेजते हैं, वह अंततः QEvent-derived क्लास के उदाहरण में एक पेलोड के रूप में समाप्त हो जाएगा।
मुद्दे का मांस जब QMetaCallEvent
घटना पाश तक पहुँच जाता है और कंटेनर एक तर्क के रूप स्लॉट में पारित कर दिया जाता है। बेशक प्रतिलिपि बनाने वालों को रास्ते में कई बार बुलाया जा सकता है।नीचे कुछ सरल कोड है कि कितनी बार प्रति निर्माता और डिफ़ॉल्ट निर्माता को दर्शाता है वास्तव में,
- एक अनुमानित साझा कॉपी-ऑन-राइट कंटेनर के डेटा के सदस्यों (QVector) के तत्वों पर
कहा जाता है है
एक कंटेनर के लिए खड़े कस्टम वर्ग पर
।
आप सुखद आश्चर्यचकित हो जाएगा :)
के बाद से क्यूटी कंटेनरों अनुमानित साझा कर रहे हैं प्रति-ऑन-राइट, उनके प्रति निर्माण नगण्य लागत है: यह सब किया है एक संदर्भ काउंटर निर्माण पर atomically वृद्धि की जाती है है । उदाहरण के लिए, डेटा सदस्यों में से कोई भी कॉपी नहीं किया गया है।
अलास, प्री -11 सी ++ अपनी बदसूरत तरफ दिखाता है: यदि स्लॉट कोड किसी भी तरह से कंटेनर को संशोधित करता है, तो स्लॉट के संदर्भों को इस तरह से पास करने का कोई तरीका नहीं है जिससे संकलक को पता चल सके कि मूल कंटेनर है अब और जरूरत नहीं है। इस प्रकार: यदि स्लॉट कंटेनर के लिए एक संदर्भ संदर्भ प्राप्त करता है, तो आप गारंटी देते हैं कि कोई प्रतियां नहीं की जाएंगी। यदि स्लॉट को कंटेनर और की एक लिखने योग्य प्रति प्राप्त होती है, तो आप इसे संशोधित करते हैं, कॉल साइट पर जिंदा उदाहरण की आवश्यकता नहीं होने के बाद से पूरी तरह से अनावश्यक प्रतिलिपि बनाई जाएगी। सी ++ में - 11 आप एक पैरामीटर संदर्भ पैरामीटर के रूप में पारित करेंगे। फ़ंक्शन कॉल में एक रावल्यू संदर्भ पास करना कॉलर में पास ऑब्जेक्ट के जीवनकाल को समाप्त करता है।
नमूना कोड उत्पादन:
"Started" copies: 0 assignments: 0 default instances: 0
"Created Foo" copies: 0 assignments: 0 default instances: 100
"Created Bar" copies: 0 assignments: 0 default instances: 100
"Received signal w/const container" copies: 0 assignments: 0 default instances: 100
"Received signal w/copy of the container" copies: 0 assignments: 0 default instances: 100
"Made a copy" copies: 100 assignments: 1 default instances: 101
"Reset" copies: 0 assignments: 0 default instances: 0
"Received signal w/const class" copies: 2 assignments: 0 default instances: 1
"Received signal w/copy of the class" copies: 3 assignments: 0 default instances: 1
//main.cpp
#include <QtCore>
class Class {
static QAtomicInt m_copies;
static QAtomicInt m_assignments;
static QAtomicInt m_instances;
public:
Class() { m_instances.fetchAndAddOrdered(1); }
Class(const Class &) { m_copies.fetchAndAddOrdered(1); }
Class & operator=(const Class &) { m_assignments.fetchAndAddOrdered(1); return *this; }
static void dump(const QString & s = QString()) {
qDebug() << s << "copies:" << m_copies << "assignments:" << m_assignments << "default instances:" << m_instances;
}
static void reset() {
m_copies = 0;
m_assignments = 0;
m_instances = 0;
}
};
QAtomicInt Class::m_instances;
QAtomicInt Class::m_copies;
QAtomicInt Class::m_assignments;
typedef QVector<Class> Vector;
Q_DECLARE_METATYPE(Vector)
class Foo : public QObject
{
Q_OBJECT
Vector v;
public:
Foo() : v(100) {}
signals:
void containerSignal(const Vector &);
void classSignal(const Class &);
public slots:
void sendContainer() { emit containerSignal(v); }
void sendClass() { emit classSignal(Class()); }
};
class Bar : public QObject
{
Q_OBJECT
public:
Bar() {}
signals:
void containerDone();
void classDone();
public slots:
void containerSlotConst(const Vector &) {
Class::dump("Received signal w/const container");
}
void containerSlot(Vector v) {
Class::dump("Received signal w/copy of the container");
v[99] = Class();
Class::dump("Made a copy");
Class::reset();
Class::dump("Reset");
emit containerDone();
}
void classSlotConst(const Class &) {
Class::dump("Received signal w/const class");
}
void classSlot(Class) {
Class::dump("Received signal w/copy of the class");
emit classDone();
//QThread::currentThread()->quit();
}
};
int main(int argc, char ** argv)
{
QCoreApplication a(argc, argv);
qRegisterMetaType<Vector>("Vector");
qRegisterMetaType<Class>("Class");
Class::dump("Started");
QThread thread;
Foo foo;
Bar bar;
Class::dump("Created Foo");
bar.moveToThread(&thread);
Class::dump("Created Bar");
QObject::connect(&thread, SIGNAL(started()), &foo, SLOT(sendContainer()));
QObject::connect(&foo, SIGNAL(containerSignal(Vector)), &bar, SLOT(containerSlotConst(Vector)));
QObject::connect(&foo, SIGNAL(containerSignal(Vector)), &bar, SLOT(containerSlot(Vector)));
QObject::connect(&bar, SIGNAL(containerDone()), &foo, SLOT(sendClass()));
QObject::connect(&foo, SIGNAL(classSignal(Class)), &bar, SLOT(classSlotConst(Class)));
QObject::connect(&foo, SIGNAL(classSignal(Class)), &bar, SLOT(classSlot(Class)));
QObject::connect(&bar, SIGNAL(classDone()), &thread, SLOT(quit()));
QObject::connect(&thread, SIGNAL(finished()), &a, SLOT(quit()));
thread.start();
a.exec();
thread.wait();
}
#include "main.moc"
हम और अधिक जानना चाहते हैं। क्या मुख्य धागे डेटा खोने के लिए स्वीकार्य है? डेटा के साथ मुख्य धागा क्या करता है, वैसे भी? लेकिन जो कुछ भी आपकी ज़रूरत है, मैं विश्वास नहीं कर सकता कि एक सरणी उत्सर्जित करना इष्टतम समाधान है। – TonyK