2013-12-17 4 views
5

मुझे क्यूटी थ्रेड और कनेक्शन के साथ कुछ परेशानी मिली है। मुझे इस विषय पर कई ट्यूटोरियल और चर्चाएं मिलीं, मैंने धागा बनाने के लिए this tutorial का पालन किया। लेकिन मुझे अभी भी समस्या है, कि थ्रेड पर प्रतीक्षा() कॉलिंग कभी वापस नहीं आती है और यूआई फ्रीज करता है।क्यूटीएचड :: प्रतीक्षा() सीधे कनेक्शन का उपयोग किए बिना वापस नहीं आती है

ऐसा ही एक सवाल यहाँ से पहले (दूसरा उदाहरण) से पूछा गया था: Qt connection type between threads: why does this work?

सवाल का पिछला संपादन में, लेखक का उल्लेख है कि वह एक गतिरोध पैदा कर दिया था। मुझे लगता है, मैं अपने आवेदन में वही करता हूं। लेकिन मैं अभी भी समझ में नहीं आता, ऐसा क्यों होता है। suggested article पढ़ना मुझे समझने में मदद नहीं करता था। मुझे अभी बात मिल गई है कि डेडलॉक्स हो सकते हैं, लेकिन मुझे नहीं पता, यह वहां क्या है या मेरे मामले में।

मैंने एक उदाहरण भी बनाया है जो मूल समस्या में कम हो गया है। इस प्रश्न के निचले हिस्से में कोड पाएं।

तो मेरे प्रश्न हैं: मेरे उदाहरण में डेडलॉक का कारण क्या है? कनेक्शन को सीधा कनेक्शन के बिना कोई समाधान है?

मैं वास्तव में किसी भी संकेत की सराहना करता हूं।

धन्यवाद!

संपादित करें:

क्योंकि टिप्पणियों के मैं इसे करने की कोशिश एक संकेत के माध्यम से रोक अनुरोध भेजने के लिए और मैं धागा पाश में एक QCoreApplication :: processEvents() कॉल गयी। लेकिन मुख्य समस्या अभी भी वही है।

EDIT2:

मैं, एक स्वीकार्य समाधान पाया घटना के बारे में थोड़ा और सोच के बाद लूप:

thread.requestStop(); 

// now instead of using wait(), we poll and keep the event loop alive 
// polling is not nice, but if it does not take a very long time 
// for the thread to finish, it is acceptable for me. 
while (thread.isRunning()) 
{ 
    // This ensures that the finished() signal 
    // will be processed by the thread object 
    QCoreApplication::processEvents();   
} 

यह वास्तव में काम करता है और कार्यकर्ता ही नियंत्रित करता है कैसे काम करना बंद कर।

इसके साथ आने के बाद, मेरे पास ठंडक मुद्दे के लिए भी एक स्पष्टीकरण है: कॉलिंग प्रतीक्षा मुख्य धागे को व्यस्त या निलंबित रखने लगता है, इसलिए यह किसी भी घटना को संसाधित नहीं करता है। चूंकि थ्रेड ऑब्जेक्ट मुख्य थ्रेड में रहता है, इसलिए थ्रेड का पूरा() सिग्नल प्राप्त होता है लेकिन कभी संसाधित नहीं होता है।

मेरी अंतर्निहित धारणा, कि thread.wait() अभी भी ईवेंट लूप को काम करेगा, स्पष्ट रूप से गलत था। लेकिन फिर, QThread :: प्रतीक्षा() फ़ंक्शन के लिए क्या अच्छा है?!

यह सिर्फ एक सिद्धांत है, लेकिन शायद किसी को यहाँ की पुष्टि या इसे झूठा साबित कर सकते हैं ...

संपादित 3 (अंतिम समाधान):

this small article पढ़ रहे हैं और एक उपवर्गीकरण समाधान implmenting के बाद, मुझे लगता है कि कि यह इस विशेष समस्या के लिए बेहतर है। इवेंट लूप की कोई ज़रूरत नहीं है और मैं एक अलग थ्रेड पर सीधे कॉल के साथ ठीक हूं और म्यूटेक्स सुरक्षा का उपयोग कर रहा हूं। यह कम कोड, समझने में आसान और डीबग करने में आसान है।

मुझे लगता है कि मैं केवल गैर-सबक्लासिंग रणनीति का उपयोग करूंगा, अगर थ्रेड के साथ और अधिक बातचीत हो तो बस शुरू करें और रोकें।


मेरे उदाहरण

कम शायद मैं कहना चाहिए, कि मैं धागा, क्योंकि अपने मूल आवेदन में, मैं बाद में फिर से शुरू करना चाहते हैं नहीं हटाते हैं, तो वास्तव में यह रोक यह रोक का मतलब है।

worker.h:

#ifndef WORKER_H 
#define WORKER_H 

#include <QObject> 
#include <QMutex> 

class Worker : public QObject 
{ 
    Q_OBJECT 

public: 
    explicit Worker(QObject* parent = NULL); 

public slots: 
    void doWork(); 
    void requestStop(); 

signals: 
    void finished(); 

private: 

    bool stopRequested; 
    QMutex mutex; 
}; 

#endif // WORKER_H 

worker.cpp:

#include "worker.h" 

#include <QThread> 
#include <iostream> 

using namespace std; 

Worker::Worker(QObject *parent) 
    : stopRequested(false) 
{ 
} 

void Worker::doWork() 
{ 
    static int cnt = 0; 

    // local loop control variable 
    // to make the usage of the mutex easier. 
    bool stopRequesteLocal = false; 

    while (!stopRequesteLocal) 
    { 
     cout << ++cnt << endl; 
     QThread::msleep(100); 

     mutex.lock(); 
     stopRequesteLocal = stopRequested; 
     mutex.unlock(); 
    } 

    cout << "Finishing soon..." << endl; 

    QThread::sleep(2); 
    emit finished(); 
} 

void Worker::requestStop() 
{ 
    mutex.lock(); 
    stopRequested = true; 
    mutex.unlock(); 
} 

मुख्य कार्यक्रम:

#include <QCoreApplication> 
#include <QThread> 
#include <QtCore> 
#include <iostream> 

#include "worker.h" 

using namespace std; 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 
    QThread thread; 
    Worker worker; 


    QObject::connect(&thread, SIGNAL(started()), &worker, SLOT(doWork())); 

    // this does not work: 
    QObject::connect(&worker, SIGNAL(finished()), &thread, SLOT(quit())); 

    // this would work: 
    //QObject::connect(&worker, SIGNAL(finished()), &thread, SLOT(quit()), Qt::DirectConnection); 

    // relocating the moveToThread call does not change anything. 
    worker.moveToThread(&thread); 

    thread.start(); 

    QThread::sleep(2); 

    worker.requestStop(); 
    cout << "Stop requested, wait for thread." << endl; 
    thread.wait(); 
    cout << "Thread finished" << endl; 

    // I do not know if this is correct, but it does not really matter, because 
    // the program never gets here. 
    QCoreApplication::exit(0); 
} 
+0

'नींद' एक क्यूटी में सुरक्षित है के रूप में सवाल पाठ करने के लिए अपने खुद के answere जोड़ा, तुम कैसे QThread :: नींद (2) कॉल कर सकते हैं; ?? – UmNyobe

+0

मुझे नहीं पता। मैं बस यह करता हूं और यह काम करता है। ;) – Kanalpiroge

+0

यह संभव नहीं है :) क्या आपने क्यूटी स्रोत संपादित किया है? –

उत्तर

0

यह नहीं दिखता है जैसे आप उस लेख पूरी तरह से पढ़ा है।

QThread* thread = new QThread; 
Worker* worker = new Worker(); 
worker->moveToThread(thread); 
connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString))); 
connect(thread, SIGNAL(started()), worker, SLOT(process())); 
connect(worker, SIGNAL(finished()), thread, SLOT(quit())); 
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); 
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); 
thread->start(); 

आपने केवल लेख पर सुझाए गए आंशिक रूप से लागू किया है।

QThread::wait()QThread::finished()doWork() से उत्सर्जित होने तक प्रतीक्षा करेगा। अगर आपको इस धागे से बाहर निकलने और मुख्य धागे पर वापस जाने की आवश्यकता है तो कृपया SIGNAL को छोड़ दें। इसके लिए आपको उस धागे का संदर्भ रखना होगा जिस पर इस ऑब्जेक्ट को स्थानांतरित किया गया है।

+0

यह मेरे लिए काम नहीं करता प्रतीत होता है। यदि मैं लाइन को आउटपुट करता हूं, तो प्रोग्राम अभी भी 'thread.wait()' पर ब्लॉक करता है। – Kanalpiroge

+0

आपके संपादन में: हाँ, क्योंकि मैं नहीं चाहता कि ऑब्जेक्ट बाद में हटा दिया जाए। लेकिन मैंने इन चीजों को देखने के लिए सिर्फ यह देखने की कोशिश की कि क्या इससे कोई फर्क पड़ता है, लेकिन ऐसा नहीं होता है। मैंने धागे पर वस्तुओं को बनाने के बजाय पॉइंटर्स का उपयोग करने का भी प्रयास किया, लेकिन यह कुछ भी नहीं बदलता है। – Kanalpiroge

+0

लूप समाप्त होने के बाद,() सिग्नल डू वर्क() के अंत में उत्सर्जित होता है। लेकिन फिर भी, प्रतीक्षा करें() वापस नहीं आती है। लेकिन मुझे यकीन है कि कार्यक्रम लूप को छोड़ देता है, क्योंकि "जल्द ही खत्म हो रहा है ..." अनुरोध को रोकने के बाद कंसोल पर दिखाई देता है()। – Kanalpiroge

2

पहला मुद्दा जो मैं देखता हूं वह यह है कि आप सिग्नल और स्लॉट का उपयोग विभिन्न धागे पर चल रहे ऑब्जेक्ट्स के बीच संवाद करने के लिए नहीं कर रहे हैं; मुख्य और नया थ्रेड जो कार्यकर्ता ऑब्जेक्ट को होस्ट करता है।

आप दूसरे सूत्र को कार्यकर्ता वस्तु ले जाने, लेकिन मुख्य धागे से कार्यकर्ता वस्तु पर एक समारोह फोन: -

thread.start(); 
QThread::sleep(2); 
worker.requestStop(); // Aaahh, this is running on the new thread!!! 

ध्यान में रखते हुए एक धागा अपनी ही ढेर और रजिस्टरों मैं वास्तव में नहीं है है कि देखें कि यह कैसे सुरक्षित है।

यदि आप सिग्नल और स्लॉट का उपयोग करते हैं, तो क्यूटी बहुत सारे थ्रेडिंग मुद्दों को संभालती है। जबकि आप दूसरे धागे को नियंत्रित करने के लिए एक चर का उपयोग करने में सक्षम होना चाहिए, यह सिग्नल और स्लॉट का उपयोग करने के लिए क्लीनर भी होगा।

ध्यान दें कि जब एक थ्रेड से सिग्नल उत्सर्जित होता है, तो प्रेषक और रिसीवर अलग थ्रेड पर होते हैं, तो प्राप्तकर्ता वस्तु के धागे पर एक संदेश पोस्ट किया जाता है।

विभिन्न थ्रेड पर ऑब्जेक्ट्स के बीच संचार करने के लिए सिग्नल और स्लॉट का उपयोग करने के लिए अपने कोड को कनवर्ट करें और आपका डेडलॉक गायब हो जाना चाहिए।

+0

मुझे लगता है कि अनुरोध Stop() फ़ंक्शन mutex के कारण थ्रेडसेफ है। और यदि यह वास्तव में एक बिंदु था, तो यह स्पष्ट नहीं करता है कि क्यों एक सीधा कनेक्शन (जिसे बुरा माना जाता है) एक कतारबद्ध कनेक्शन (जो आपको उपयोग करना चाहिए) के दौरान काम करता है। – Kanalpiroge

+1

म्यूटेक्स फ़ंक्शन में परिवर्तित होने वाले चर को सुरक्षित करता है, लेकिन उस फ़ंक्शन में उपयोग किए जा रहे स्टैक और रजिस्टरों का नहीं। हर तरह से, एक म्यूटेक्स के साथ एक साझा चर का उपयोग करें, लेकिन मेरा सुझाव है कि आप कार्य को सीधे कॉल करने के बजाए कार्यकर्ता ऑब्जेक्ट पर एक स्लॉट कॉल करें। सीधा कनेक्शन के लिए, मुझे उम्मीद है कि यह सिर्फ भाग्य है और बाद में आपको समस्याएं पैदा करने का इंतजार कर रहा है। अगर कोई अलग-अलग जानता है, तो मुझे यह समझने में दिलचस्पी होगी कि यह कैसे काम कर सकता है। – TheDarkKnight

+1

@ Kanalpiroge Merlin कम से कम इस बिंदु पर, इस स्थान पर है। आपको सिग्नल के माध्यम से अनुरोध करने की आवश्यकता है। – UmNyobe

संबंधित मुद्दे