Qt
थ्रेडिंग और कंसीडर
खोज…
टिप्पणियों
कुछ नोट जो पहले से ही यहां और यहां आधिकारिक डॉक्स में उल्लिखित हैं :
- यदि किसी वस्तु में माता-पिता हैं, तो उसे माता-पिता के समान धागे में होना चाहिए, अर्थात उसे एक नए धागे में नहीं ले जाया जा सकता है, न ही आप किसी माता-पिता को किसी वस्तु में सेट कर सकते हैं यदि माता-पिता और वस्तु अलग-अलग धागे में रहते हैं
- जब किसी वस्तु को एक नए धागे में ले जाया जाता है, तो उसके सभी बच्चे भी नए धागे में चले जाते हैं
- आप केवल वस्तुओं को एक नए धागे में धकेल सकते हैं। आप उन्हें एक नए धागे में नहीं खींच सकते, यानी आप केवल उस थ्रेड से
moveToThread
कर सकते हैं जहां ऑब्जेक्ट वर्तमान में रह रहा है
क्यूथ्रेड का मूल उपयोग
QThread
एक प्लेटफ़ॉर्म थ्रेड के लिए एक हैंडल है। यह आपको अपने जीवनकाल की निगरानी करके धागे का प्रबंधन करने देता है, और अनुरोध करता है कि यह अपना काम पूरा कर ले।
ज्यादातर मामलों में कक्षा से बाहर निकलने की सिफारिश नहीं की जाती है। डिफ़ॉल्ट run
पद्धति एक ईवेंट लूप शुरू करती है जो घटनाओं को कक्षा में रहने वाली वस्तुओं के लिए भेज सकती है। क्रॉस-थ्रेड सिग्नल-स्लॉट कनेक्शन को QMetaCallEvent
को लक्ष्य ऑब्जेक्ट पर QMetaCallEvent
कार्यान्वित किया जाता है।
एक QObject
उदाहरण को एक थ्रेड में ले जाया जा सकता है, जहां यह अपने ईवेंट को संसाधित करेगा, जैसे टाइमर इवेंट या स्लॉट / विधि कॉल।
एक सूत्र पर काम करने के लिए, पहले अपने स्वयं के कार्यकर्ता वर्ग बनाएं जो QObject
से QObject
। फिर इसे धागे में स्थानांतरित करें। ऑब्जेक्ट QMetaObject::invokeMethod()
का उपयोग करके अपने कोड को स्वचालित रूप से चला सकता है।
#include <QObject>
class MyWorker : public QObject
{
Q_OBJECT
public:
Q_SLOT void doWork() {
qDebug() << "doWork()" << QThread::currentThread();
// and do some long operation here
}
MyWorker(QObject * parent = nullptr) : QObject{parent} {}
};
class MyController : public QObject
{
Q_OBJECT
Worker worker;
QThread workerThread;
public:
MyController() {
worker.moveToThread(&workerThread);
// provide meaningful debug output
workerThread.setObjectName("workerThread");
workerThread.start();
// the thread starts the event loop and blocks waiting for events
}
~MyController() {
workerThread.quit();
workerThread.wait();
}
void operate() {
// Qt::QueuedConnection ensures that the slot is invoked in its own thread
QMetaObject::invokeMethod(&worker, "doWork", Qt::QueuedConnection);
}
};
यदि आपका कार्यकर्ता अल्पकालिक है और केवल मौजूद है, जबकि इसका काम किया जा रहा है, तो QtConcurrent::run
माध्यम से थ्रेड पूल में निष्पादन के लिए एक फ़नकार या थ्रेड-सुरक्षित विधि प्रस्तुत करना सबसे अच्छा है।
QtConcurrent रन
यदि आप म्यूटेक्स या सेमाफोर जैसे जटिल क्यूटीह्रेड्स और निम्न-स्तरीय प्राइमेटिव का प्रबंधन करते हैं, तो क्यूटी समवर्ती नाम स्थान वह है जो आप खोज रहे हैं। इसमें ऐसी कक्षाएं शामिल हैं जो अधिक उच्च-स्तरीय थ्रेड प्रबंधन की अनुमति देती हैं।
आइए देखें समवर्ती रन। QtConcurrent::run()
एक नए थ्रेड में फ़ंक्शन को चलाने की अनुमति देता है। आप इसका उपयोग कब करना चाहेंगे? जब आपके पास कुछ लंबा ऑपरेशन होता है और आप मैन्युअल रूप से थ्रेड नहीं बनाना चाहते हैं।
अब कोड:
#include <qtconcurrentrun.h>
void longOperationFunction(string parameter)
{
// we are already in another thread
// long stuff here
}
void mainThreadFunction()
{
QFuture<void> f = run(longOperationFunction, "argToPass");
f.waitForFinished();
}
इसलिए चीजें सरल हैं: जब हमें किसी अन्य फ़ंक्शन को किसी अन्य थ्रेड में चलाने की आवश्यकता होती है, तो बस QtConcurrent::run
, पास फ़ंक्शन और उसके मापदंडों को कॉल करें और यही वह है!
QFuture
हमारे अतुल्यकालिक गणना का परिणाम प्रस्तुत करता है। QtConcurrent::run
मामले में QtConcurrent::run
हम कार्य निष्पादन को रद्द नहीं कर सकते।
अन्य थ्रेड्स से स्लॉट को आमंत्रित करना
जब Qt ईवेंट लूप का उपयोग ऑपरेशन करने के लिए किया जाता है और एक गैर- Qt-saavy उपयोगकर्ता को उस ईवेंट लूप के साथ सहभागिता करने की आवश्यकता होती है, तो एक और थ्रेड से नियमित इनवोकेशन को संभालने के लिए स्लॉट लिखना अन्य उपयोगकर्ताओं के लिए चीजों को सरल बना सकता है।
main.cpp:
#include "OperationExecutioner.h"
#include <QCoreApplication>
#include <QThread>
int main(int argc, char** argv)
{
QCoreApplication app(argc, argv);
QThread thrd;
thrd.setObjectName("thrd");
thrd.start();
while(!thrd.isRunning())
QThread::msleep(10);
OperationExecutioner* oe = new OperationExecutioner;
oe->moveToThread(&thrd);
oe->doIt1(123,'A');
oe->deleteLater();
thrd.quit();
while(!thrd.isFinished())
QThread::msleep(10);
return 0;
}
OperationExecutioner.h:
#ifndef OPERATION_EXECUTIONER_H
#define OPERATION_EXECUTIONER_H
#include <QObject>
class OperationExecutioner : public QObject
{
Q_OBJECT
public slots:
void doIt1(int argi, char argc);
};
#endif // OPERATION_EXECUTIONER_H
OperationExecutioner.cpp:
#include "OperationExecutioner.h"
#include <QMetaObject>
#include <QThread>
#include <QDebug>
void OperationExecutioner::doIt1(int argi, char argc)
{
if (QThread::currentThread() != thread()) {
qInfo() << "Called from thread" << QThread::currentThread();
QMetaObject::invokeMethod(this, "doIt1", Qt::QueuedConnection,
Q_ARG(int,argi), Q_ARG(char,argc));
return;
}
qInfo() << "Called from thread" << QThread::currentThread()
<< "with args" << argi << argc;
}
OperationExecutioner.pro:
HEADERS += OperationExecutioner.h
SOURCES += main.cpp OperationExecutioner.cpp
QT -= gui