यहाँ one example of how to use QThread correctly है है, लेकिन यह इसके साथ कुछ मुद्दों पर है, जो में परिलक्षित होते हैं है टिप्पणियाँ। विशेष रूप से, जिस क्रम में स्लॉट निष्पादित किए जाते हैं, उसे सख्ती से परिभाषित नहीं किया जाता है, इससे विभिन्न समस्याएं हो सकती हैं। 6 अगस्त, 2013 को पोस्ट की गई टिप्पणी इस मुद्दे से निपटने का एक अच्छा विचार देती है। मैं अपने प्रोग्राम में ऐसा कुछ उपयोग करता हूं, और स्पष्टीकरण के लिए यहां कुछ उदाहरण कोड है।
मूल विचार समान है: मैं एक QThread उदाहरण बनाता हूं जो मेरे मुख्य धागे में रहता है, एक मजदूर वर्ग उदाहरण जो मैंने बनाए गए नए धागे में रहता है, और फिर मैं सभी संकेतों को जोड़ता हूं।
void ChildProcesses::start()
{
QThread *childrenWatcherThread = new QThread();
ChildrenWatcher *childrenWatcher = new ChildrenWatcher();
childrenWatcher->moveToThread(childrenWatcherThread);
// These three signals carry the "outcome" of the worker job.
connect(childrenWatcher, SIGNAL(exited(int, int)),
SLOT(onChildExited(int, int)));
connect(childrenWatcher, SIGNAL(signalled(int, int)),
SLOT(onChildSignalled(int, int)));
connect(childrenWatcher, SIGNAL(stateChanged(int)),
SLOT(onChildStateChanged(int)));
// Make the watcher watch when the thread starts:
connect(childrenWatcherThread, SIGNAL(started()),
childrenWatcher, SLOT(watch()));
// Make the watcher set its 'stop' flag when we're done.
// This is performed while the watch() method is still running,
// so we need to execute it concurrently from this thread,
// hence the Qt::DirectConnection. The stop() method is thread-safe
// (uses a mutex to set the flag).
connect(this, SIGNAL(stopped()),
childrenWatcher, SLOT(stop()), Qt::DirectConnection);
// Make the thread quit when the watcher self-destructs:
connect(childrenWatcher, SIGNAL(destroyed()),
childrenWatcherThread, SLOT(quit()));
// Make the thread self-destruct when it finishes,
// or rather, make the main thread delete it:
connect(childrenWatcherThread, SIGNAL(finished()),
childrenWatcherThread, SLOT(deleteLater()));
childrenWatcherThread->start();
}
कुछ पृष्ठभूमि:
ChildProcesses वर्ग, एक बच्चे की प्रक्रिया प्रबंधक है कि अंडे के साथ नए बच्चे प्रक्रियाओं() कॉल शुरू होता है वर्तमान में चल रहे और इतने पर प्रक्रियाओं की सूची रहती है। हालांकि, इसे बच्चों के राज्यों का ट्रैक रखने की आवश्यकता है, जिसका मतलब है कि लिनक्स पर प्रतीक्षापिड() कॉल या विंडोज पर WaitForMultipleObjects का उपयोग करना है। मैं इन्हें टाइमर का उपयोग करके गैर-अवरुद्ध मोड में कॉल करता था, लेकिन अब मुझे अधिक त्वरित प्रतिक्रिया चाहिए, जिसका अर्थ ब्लॉकिंग मोड है। यह कैसे काम करता यहाँ
class ChildrenWatcher: public QObject {
Q_OBJECT
private:
QMutex mutex;
bool stopped;
bool isStopped();
public:
ChildrenWatcher();
public slots:
/// This is the method which runs in the thread.
void watch();
/// Sets the stop flag.
void stop();
signals:
/// A child process exited normally.
void exited(int ospid, int code);
/// A child process crashed (Unix only).
void signalled(int ospid, int signal);
/// Something happened to a child (Unix only).
void stateChanged(int ospid);
};
: यह जहां धागा भूमिका शुरू होती है
ChildrenWatcher वर्ग इस प्रकार परिभाषित किया गया है।। जब यह सब सामान शुरू हो जाता है, तो ChildProcess :: प्रारंभ() विधि को कॉल किया जाता है (ऊपर देखें)। यह एक नया QThread और एक नया ChildrenWatcher बनाता है, जिसे तब नए धागे में ले जाया जाता है। फिर मैं तीन संकेतों को जोड़ता हूं जो मेरे प्रबंधक को अपने बच्चों की प्रक्रियाओं के भाग्य के बारे में सूचित करते हैं (बाहर निकल/संकेतित/ईश्वर-जानता-क्या हुआ)। फिर मुख्य मज़ा शुरू होता है।
मैं QThread :: start() को ChildrenWatcher :: watch() विधि से कनेक्ट करता हूं, इसलिए जैसे ही धागा तैयार हो जाता है, इसे शुरू किया जाता है। चूंकि दर्शक नए धागे में रहता है, वहीं जहां घड़ी() विधि निष्पादित की जाती है (स्लॉट कनेक्शन स्लॉट को कॉल करने के लिए उपयोग किया जाता है)।
फिर मैं Qt :: DirectConnection का उपयोग कर ChildWroccher :: stop() स्लॉट को ChildProcesses :: stop() सिग्नल कनेक्ट करता हूं क्योंकि मुझे इसे अतुल्यकालिक रूप से करने की आवश्यकता है। इसकी आवश्यकता है इसलिए जब मेरा चाइल्डप्रोसेस मैनेजर की आवश्यकता नहीं है तो मेरा धागा बंद हो जाता है। बंद() विधि इस प्रकार है:
void ChildrenWatcher::stop()
{
mutex.lock();
stopped = true;
mutex.unlock();
}
और फिर ChildrenWatcher :: घड़ी():
void ChildrenWatcher::watch()
{
while (!isStopped()) {
// Blocking waitpid() call here.
// Maybe emit one of the three informational signals here too.
}
// Self-destruct now!
deleteLater();
}
ओह, और isStopped() विधि में एक म्युटेक्स उपयोग करने के लिए सिर्फ एक सुविधाजनक तरीका है जबकि() हालत:
bool ChildrenWatcher::isStopped()
{
bool stopped;
mutex.lock();
stopped = this->stopped;
mutex.unlock();
return stopped;
}
तो क्या यहाँ होता है मैं बंद कर दिया ध्वज सेट कि जब मैं खत्म करने की जरूरत है, और फिर अगली बार isStopped() यह गलत वापस आती है और धागा समाप्त होता है कहा जाता है।
तो क्या होता है जब घड़ी() लूप समाप्त होता है? यह deleteLater() को कॉल करता है, इसलिए ऑब्जेक्ट स्वयं को नष्ट कर देता है जैसे ही नियंत्रण थ्रेड इवेंट लूप पर वापस आ जाता है जो हटाए जाने के बाद ठीक होता है() कॉल (जब घड़ी() रिटर्न)। ChildProcesses पर वापस जाएं :: प्रारंभ करें(), आप देख सकते हैं कि थैचर के हटाए गए() स्लॉट से वॉचर के नष्ट() सिग्नल से कनेक्शन है। इसका मतलब यह है कि जब वॉचर किया जाता है तो थ्रेड स्वचालित रूप से खत्म हो जाता है।और जब यह समाप्त हो जाता है, तो यह भी स्वयं को नष्ट कर देता है क्योंकि इसका अपना पूरा() सिग्नल इसके डिलीटलाटर() स्लॉट से जुड़ा होता है।
यह काफी एक ही विचार के रूप में माया तैनात है, लेकिन क्योंकि मैं आत्म विनाश मुहावरा इस्तेमाल करते हैं, मैं अनुक्रम जिसमें स्लॉट कहा जाता है पर निर्भर करते हैं की जरूरत नहीं है। यह हमेशा पहले स्वयं को नष्ट कर देता है, बाद में थ्रेड रोकता है, फिर यह स्वयं भी नष्ट हो जाता है। मैं कार्यकर्ता में एक पूर्ण() सिग्नल को परिभाषित कर सकता हूं, और फिर इसे अपने स्वयं के डिलीटलाटर() से कनेक्ट कर सकता हूं, लेकिन इसका मतलब केवल एक कनेक्शन होगा। चूंकि मुझे किसी अन्य उद्देश्य के लिए एक पूर्ण() सिग्नल की आवश्यकता नहीं है, इसलिए मैंने केवल कार्यकर्ता से हटाना() को कॉल करना चुना है।
माया भी कहा गया है कि आप कार्यकर्ता निर्माता में नए QObjects आवंटित नहीं चाहिए क्योंकि वे धागा आप के लिए कार्यकर्ता ले जाने में नहीं रहना होगा। मैं कहूंगा कि वैसे भी ऐसा करें क्योंकि ओओपी काम करता है। बस सुनिश्चित करें कि उन सभी QObjects कार्यकर्ता के बच्चों (अर्थात, QObject (QObject *) निर्माता का उपयोग है) कर रहे हैं - moveToThread() वस्तु ले जाया जा रहा के साथ-साथ सभी बच्चों को ले जाता है। यदि आपको वास्तव में QObjects की आवश्यकता है जो आपके ऑब्जेक्ट के बच्चे नहीं हैं, तो अपने कार्यकर्ता में moveToTread() को ओवरराइड करें ताकि यह सभी आवश्यक सामान भी चला सके।
यह ध्यान देने योग्य है कि 4.8 राज्यों के तहत नए प्रलेखन एक QThread का उपयोग करें और सक्रिय रूप से करने के लिए उचित तरीके से एक QThread वस्तु से पाने सिर्फ एक कार्यकर्ता वस्तु/धागा बनाने के लिए के पुराने तरीके से हतोत्साहित करता है। http://qt-project.org/doc/qt-4.8/qthread.html#details – g19fanatic
डॉक केवल शुरू QThread उपवर्ग में नये स्लॉट हतोत्साहित किया जाता है कहते हैं। QThread कक्षा से प्राप्त करने का कोई उल्लेख नहीं किया। QThread से व्युत्पन्न डेल्फी/सी ++ बिल्डर के टीटीएचड के समान प्रतिमान का पालन करता है। –
http://woboq.com/blog/qthread-you-were-not-doing-so-wrong.html –