2013-10-29 6 views
5

नीचे दिए गए उदाहरण (क्यूटी जीयूआई आवेदन के अंदर) एक नया धागा शुरू कर दिया है (एक घटना पाश जिसमें मैं कुछ काम करना चाहते हैं के साथ) में:QThread के साथ क्या होता है जब उचित प्रतीक्षा() कॉल के बिना एप्लिकेशन बंद किया जा रहा है?

void doWork() 
{ 
    QThread* workerThread = new QThread(); 

    Worker* worker = new Worker(); 
    worker->moveToThread(workerThread); 

    connect(workerThread, SIGNAL(started()), worker, SLOT(startWork())); 
    connect(worker, SIGNAL(finished()), workerThread, SLOT(quit())); 

    connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater())); 
    connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater())); 

    workerThread->start(); 
} 

startWork() एक लंबी चलने वाली आपरेशन किया जा सकता है, जिसके दौरान आवेदन बंद किया जा सकता है।

मुझे उम्मीद है कि आवेदन startWork() को workerThread पर निष्पादित किया जा रहा है। ऐसा लगता है कि, जब मैं अंतिम एप्लिकेशन विंडो बंद करता हूं, तो workerThread तत्काल चला जाता है (लंबे समय तक चलने वाले ऑपरेशन के दौरान) और एप्लिकेशन बिना किसी समस्या के बंद हो जाता है।

सवाल पैदा हुआ:

  1. क्यों workerThread तुरंत मिटा दिया गया था?
    • क्या यह कुछ माता-पिता/बच्चे का मुद्दा है?
    • कैसे क्यूटी ऐसी स्थिति को संभालती है?
  2. क्या यह प्रोग्रामर गलती है, QThread (अंततः) पर wait() पर कॉल न करें?
    • यदि भी ऐसा है, तो मैंने को aboutToQuit() के लिए स्लॉट के अंदर wait() करने का प्रयास किया और लंबे समय तक चलने वाले ऑपरेशन के बाद आवेदन बंद नहीं किया गया था (ऊपर के रूप में सेटअप के साथ)। केवल quit(); wait(); (निर्दिष्ट स्लॉट के अंदर) ने एप्लिकेशन को बंद करने की अनुमति दी। क्यूं कर?
+0

शायद थ्रेड को 'टर्मिनेट' कॉल है –

उत्तर

6

QThread, मूल रूप से, एक लंबे समय से चलने वाली एपीआई बग है: यह हमेशा विनाशकारी स्थिति में नहीं होता है। सी ++ में, एक वस्तु को विनाशकारी स्थिति में माना जाता है जब यह अपने विनाशक को आमंत्रित करना सुरक्षित होता है। चल रहे QThread को नष्ट करना एक त्रुटि है। एक QThread केवल एक धागा नियंत्रक है, यह "धागा" नहीं है। इस बारे में सोचें कि QFile कार्य करता है: आप इसे किसी भी समय नष्ट कर सकते हैं, चाहे वह खुला हो या नहीं।यह वास्तव में एक संसाधन के रूप में एक फ़ाइल की धारणा encapsulates। एक QThread देशी (सिस्टम) के चारों ओर एक आवरण का बहुत पतला धागा है: जब आप इसे संहार, यह समाप्त नहीं करता है और न ही देशी धागा के निपटान अगर वहाँ एक है। यह एक संसाधन रिसाव है (धागे ओएस संसाधन हैं), और लोग इस मुद्दे पर बार-बार यात्रा करते हैं।

आवेदन के main() समारोह रिटर्न, C/C++ रनटाइम लायब्रेरी के अपने कार्यान्वयन आवेदन के धागे के सभी समाप्त करने के लिए, प्रभावी रूप से आवेदन की सम्पूर्णता को समाप्त होता है। चाहे वह वही व्यवहार है जो आप चाहते हैं। आप quit() और wait() आपके घटना पाश समय से चल रहे धागा करने वाले रहे हैं। एक घटना पाश बिना धागे के लिए, quit() नो-सेशन और आप अपने खुद के छोड़ने ध्वज को लागू करना चाहिए। आप wait() धागे पर इससे पहले कि आप संहार करना होगा। यह दौड़ की स्थिति को रोकने के लिए है।

नीचे QThread के लिए एक सुरक्षित आवरण है। यह एक अंतिम श्रेणी है, क्योंकि आप run को पुन: कार्यान्वित नहीं कर सकते हैं। यह महत्वपूर्ण है, क्योंकि रन के पुनर्मूल्यांकन को इस तरह से किया जा सकता है जो quit को नो-ऑप बनाता है, contract of the class तोड़ता है। , धागा आलसी quit() होगा सभी कार्यकर्ता धागे main से

#include <QCoreApplication> 

int main(int argc, char ** argv) { 
    QCoreApplication app(argc, argv); 
    QObject worker1, worker2; 
    Thread thread1, thread2; 
    // Style 1 
    ThreadQuitter quitter; 
    quitter << thread1 << thread2; 
    // Style 2 
    ThreadQuitter quitterB(ThreadQuitter::List() << &thread1 << &thread2); 
    // 
    worker1.moveToThread(&thread1); 
    worker2.moveToThread(&thread2); 
    thread1.start(); 
    thread2.start(); 

    QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection); 
    return app.exec(); 
} 

लौटने पर:

#include <QThread> 
#include <QPointer> 

class Thread : public QThread { 
    using QThread::run; // final 
public: 
    Thread(QObject * parent = 0) : QThread(parent) {} 
    ~Thread() { quit(); wait(); } 
}; 

class ThreadQuitter { 
public: 
    typedef QList<QPointer<Thread>> List; 
private: 
    List m_threads; 
    Q_DISABLE_COPY(ThreadQuitter) 
public: 
    ThreadQuitter() {} 
    ThreadQuitter(const List & threads) : m_threads(threads) {} 
    ThreadQuitter(List && threads) : m_threads(std::move(threads)) {} 
    ThreadQuitter & operator<<(Thread* thread) { 
    m_threads << thread; return *this; 
    } 
    ThreadQuitter & operator<<(Thread& thread) { 
    m_threads << &thread; return *this; 
    } 
    ~ThreadQuitter() { 
     foreach(Thread* thread, m_threads) thread->quit(); 
    } 
}; 

यह इस प्रकार के रूप में इस्तेमाल किया जा सकता। यह धागे समानांतर में नीचे जाने की अनुमति देता है। फिर, thread2.~Thread कि धागा समाप्त होने की प्रतीक्षा करेंगे, तब thread1.~Thread भी ऐसा ही होगा। थ्रेड अब चले गए हैं, ऑब्जेक्ट्स थ्रेडलेस हैं और सुरक्षित रूप से नष्ट हो सकते हैं: worker2.~QObject पहले से लागू किया गया है, इसके बाद worker1.~QObject है।

1

1) यह माता पिता/बच्चे मुद्दा है?

आपके कोड के मामले में नहीं - आप QThread का पालन नहीं कर रहे हैं। यदि आपके पास अन्य थ्रेड चल रहे हैं तो क्यूटी आपको मुख्य थ्रेड को समाप्त करने के लिए पसंद नहीं करता है। आपको मानक आउटपुट में शिकायत करने की संभावना है कि एप्लिकेशन समाप्त होने पर अन्य थ्रेड अभी भी चल रहा था। हालांकि, क्यूटी अन्य धागे को मार डालेगा, यही कारण है कि कॉल करने के लिए एक फ़ंक्शन है और थ्रेड को ठीक से समाप्त करने की प्रतीक्षा करें।

2) क्या यह प्रोग्रामर गलती है कि प्रतीक्षा() को कॉल न करें?

हां। यदि आपको थ्रेड के साथ समस्याएं ठीक से नहीं छोड़ रही हैं, तो ऐसा इसलिए है क्योंकि आप इसे सही तरीके से प्रबंधित नहीं कर रहे हैं, इस स्थिति में आप एक और प्रश्न खोल सकते हैं और कोड को दिखा सकते हैं कि आप छोड़ने से पहले प्रतीक्षा कैसे कर रहे हैं।

जब मैं पिछले आवेदन विंडो को बंद, workerThread तुरंत चला गया है

नोट QApplication में एक समारोह है कि वहाँ setQuitOnLastWindowClosed बुलाया, तो आप गलत पर सेट एप्लिकेशन स्वचालित रूप से बंद करने पर छोड़ने को रोकने के लिए कर सकते हैं जो आखिरी खिड़की

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

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