2015-02-01 7 views
5

छोड़ने पर नहीं रुकता है मैं कैमरे से वीडियो फ़ीड (ओपनसीवी का उपयोग करके) को कैप्चर करने के लिए एक साधारण क्यूटी प्रोग्राम लिख रहा हूं। मैं QThread ऑब्जेक्ट का उपयोग कर रहा हूं जो लूप, छवियों को कैप्चर करना और उन्हें MainWindow ऑब्जेक्ट पर खिला रहा है। यह काम कर रहा है जैसा कि यह करना चाहिए।मल्टीथ्रेड क्यूटी एप्लिकेशन

समस्या यह है कि जब मैं बंद करता हूं, एप्लिकेशन (यानी "एक्स" दबाकर) कैमरा कैप्चरिंग थ्रेड बंद हो जाता है और गुई गायब हो जाता है। लेकिन कार्यक्रम अभी भी पृष्ठभूमि में चल रहा है। मुझे एप्लिकेशन आउटपुट में चेतावनी भी मिल रही है:

QThread: थ्रेड अभी भी चल रहा है, जबकि नष्ट हो गया है।

इसे छोड़ते समय मैं एप्लिकेशन को पूरी तरह से कैसे रोक सकता हूं?

main.cpp

#include <QApplication> 
#include "application.h" 

using namespace cv; 

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 

    Application app; 
    app.init(); 

    return a.exec(); 
} 

application.h

#include "mainwindow.h" 
#include "camerathread.h" 
#include "mathandler.h" 
#include "tools.h" 
#include "opencv2/core/core.hpp" 

#ifndef APPLICATION 
#define APPLICATION 

class Application : public MatHandler{ 
    MainWindow w; 
    CameraThread ct; 
public: 
    Application() { 
     w.setFixedSize(800,600); 
    } 

    void init() { 
     ct.setMatHandler(this); 
     ct.start(); 
     w.show(); 
    } 

    void handleMat(cv::Mat mat) { 
     QImage qImage = toQImage(mat); 
     w.setImage(qImage); 
    } 
}; 

#endif // APPLICATION 

camerathread

#include <QThread> 
#include "mathandler.h" 
#include "opencv2/highgui/highgui.hpp" 

#ifndef CAMERATHREAD 
#define CAMERATHREAD 

class CameraThread : public QThread { 
    MatHandler *matHandler; 
public: 
    ~CameraThread() { 
    } 

    void setMatHandler(MatHandler *h) { 
     matHandler = h; 
    } 

private: void run() { 
     cv::VideoCapture vc(0); 

     if (vc.isOpened()) { 
      for(;;) { 
       cv::Mat img; 
       vc >> img; 
       matHandler->handleMat(img); 
      } 
     } 
    } 
}; 

#endif // CAMERATHREAD 

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

+0

यह देखने के लिए जांचें कि यूआई और कैमरा थ्रेड के अलावा अन्य धागे चल रहे हैं या नहीं। यह संभव है कि आप जिन एपीआई को अन्य धागे का उपयोग कर रहे हैं। –

+0

मुझे यकीन नहीं है कि इसके लिए कैसे जांचें ... क्या आप कृपया समझा सकते हैं? – gromit190

+0

चलने वाले धागे पर जांच करने से आप जिस आईडीई का उपयोग कर रहे हैं उस पर निर्भर करता है (यदि यह इसके नमक के लायक है)। उदाहरण के लिए, यह खोज: https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=how%20to%20see%20running%20threads%20in%20eclipse ने इस परिणाम को जन्म दिया : http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.mat.ui.help%2Ftasks%2Fanalyzingthreads.html लेकिन फिर, यह आपके आईडीई पर निर्भर करता है। मैंने बस नमूना दृश्य/डब्ल्यू ग्रहण का प्रदर्शन किया। –

उत्तर

3

आपके कोड के साथ कुछ प्रमुख समस्याएं हैं।

while(!finishThread) 
{ 
    cv::Mat img; 
    vc >> img; 
    matHandler->handleMat(img); 
} 

आप true को finishThread स्थापित करना चाहिए जब अनुप्रयोग को बंद करने जा रहा है: अपने चलाने के समारोह में सबसे पहले पाश के लिए अंतहीन रोक कभी नहीं करने के लिए जब तक आप की तरह अपने स्वयं के द्वारा धागा समाप्ति का प्रबंधन अपने धागा कारण होगा। बस एक स्लॉट प्रदान करें जिसमें आपने finishThread के लिए मान निर्धारित किया है। जब आप थ्रेड को समाप्त करना चाहते हैं तो उस स्लॉट से जुड़े सिग्नल को true मान से कनेक्ट करें। उसके बाद धागा कुछ सेकंड के लिए ठीक से समाप्त होने की प्रतीक्षा करें और यदि यह समाप्त नहीं किया समाप्त करने के लिए उसे बलपूर्वक:

emit setThreadFinished(true); //Tell the thread to finish 
if(!ct->wait(3000)) //Wait until it actually has terminated (max. 3 sec) 
{ 
    ct->terminate(); //Thread didn't exit in time, probably deadlocked, terminate it! 
    ct->wait(); //We have to wait again here! 
} 

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

एक अन्य बिंदु यह है कि आप अपनी कक्षा QObject से प्राप्त करने के लिए बेहतर हैं और moveToThread का उपयोग करें। आप अपने वर्ग के निर्माता से कर सकते हैं:

th = new QThread(); 

this->setParent(0); 
this->moveToThread(th); 

QObject::connect(th,SIGNAL(started()),this,SLOT(OnStarted())); 
QObject::connect(th,SIGNAL(finished()),this,SLOT(OnFinished())); 

th->start(); 

आपका प्रारंभ और समाप्ति कार्यों क्रमशः OnStarted() और OnFinished() स्लॉट में किया जाना चाहिए। आपके पास एक कार्यकर्ता कार्य हो सकता है जिसमें आप दोहराव वाले ऑपरेशन चलाते हैं।

इसके अलावा आपके Application वर्ग के विनाशक में किसी भी तरह से धागे को छोड़ दिया गया है।

+0

फीडबैक के लिए धन्यवाद, यह बहुत जरूरी है क्योंकि मैं (जैसा कि आपने शायद पहले ही महसूस किया है) सी ++ और क्यूटी प्रोग्रामिंग में एक नौसिखिया है। लेकिन एक बात मेरे लिए अस्पष्ट नहीं है। जब मैं एप्लिकेशन को रोकने के लिए सार्वजनिक शून्य विधि का उपयोग कर सकता हूं तो मुझे कैमरा थ्रेड में सार्वजनिक स्लॉट का उपयोग क्यों करना चाहिए? पेशेवर/विपक्ष क्या हैं? – gromit190

+1

यदि आप एप्लिकेशन को रोकने के लिए किसी विधि का उपयोग करते हैं तो आपको इसे 'ct-> setfinished (true);' 'एप्लिकेशन' से सीधे कॉल करना होगा जो वास्तव में खतरनाक है। ऐसा इसलिए है क्योंकि वे दो अलग-अलग धागे में हैं और एक दो चर से एक चर का उपयोग एक साथ अपरिभाषित व्यवहार की ओर जाता है। जब आप थ्रेड को रोकने के लिए सिग्नल/स्लॉट तंत्र का उपयोग करते हैं, तो आप सुनिश्चित करते हैं कि चर केवल एक थ्रेड ('कैमरा थ्रेड' से एक्सेस किया गया है)। किसी अन्य थ्रेड में किसी ऑब्जेक्ट का फ़ंक्शन कभी भी कॉल न करें। – Nejat

+0

नोट किया गया, धन्यवाद। मुख्य मुद्दे पर; मैंने आपके द्वारा सुझाए गए एप्लिकेशन डिकॉन्स्ट्रक्टर को सीटी-> स्टॉप कोड जोड़ा। थ्रेड के deconstructor में QThread :: निकास() भी जोड़ा। मुख्य विंडो बंद करने के बाद भी एप्लिकेशन चल रहा है ... – gromit190

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