2010-01-18 18 views
26

moveToThread का उपयोग कर किसी ऑब्जेक्ट को क्यूटी में एक थ्रेड से दूसरे स्थानांतरित करने का क्या अर्थ है? सब कुछ moveToThread का उपयोग करने से पहले भी काम करता प्रतीत होता है, जो ऑब्जेक्ट को एक थ्रेड (जीयूआई थ्रेड) से दूसरे थ्रेड (काम) तक ले जाता है और क्यूटी: ऑब्जेक्ट पर उपयुक्त स्लॉट को कॉल करता है।क्यूटी थ्रेड में सिग्नलिंग, एक जीयूआई थ्रेड है?

क्या ऑब्जेक्ट रहता है, जीयूआई थ्रेड या वर्कर थ्रेड के कारण कोई अंतर है?

संपादित करें: मैं एक छोटे से कार्यक्रम बनाया, लेकिन मुझे समझ नहीं आता कैसे QThread सिग्नल और स्लॉट समारोह के साथ काम करता है, मुझे खुशी होगी अगर आप समझा सकता है क्या उदाहरण

#include <QtGui/QApplication> 
#include <QPushButton> 
#include <QHBoxLayout> 
#include <QLineEdit> 
#include <QString> 
#include "mythread.h" 
//GUI calls a thread to do some job and sub update the text box once it is done 
int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 
    QWidget w; 
    QHBoxLayout * pH = new QHBoxLayout(&w); 
    QPushButton * pushButton = new QPushButton("asdad"); 
    QLineEdit * lineEdit = new QLineEdit("AAA"); 
    pH->addWidget(pushButton); 
    pH->addWidget(lineEdit); 
    w.setLayout(pH); 
    w.show(); 
    MyThread thread; 
    qDebug("Thread id %d",(int)QThread::currentThreadId()); 
    QObject::connect(pushButton,SIGNAL(clicked()),&thread,SLOT(callRun())) ; 
    QObject::connect(&thread,SIGNAL(signalGUI(QString)),lineEdit,SLOT(setText(QString))); 
    return a.exec(); 
} 

#ifndef MYTHREAD_H 
#define MYTHREAD_H 

#include <QThread> 
#include <QMutex> 

class MyThread : public QThread 
{ 
    Q_OBJECT 
public: 
    MyThread(); 
public slots: 
    void callRun(); 
    void run(); 
signals: 
    void signalGUI(QString); 
private: 
    QMutex mutex; 

}; 

#endif // MYTHREAD_H 


#include "mythread.h" 
#include <QDebug> 
#include <QString> 
#include <QMutexLocker> 

MyThread::MyThread() 
{ 
} 
void MyThread::callRun() 
{ 

    qDebug("in thread"); 
    if(!isRunning()) 
    { 
     this->start(LowestPriority); 
     exec(); 
    } 
    else 
    { 
     run(); 
    } 

} 
void MyThread::run() 
{ 
    QMutexLocker fn_scope(&mutex); 
    static int a = 0; 
    ++a; 
    qDebug("Thread id inside run %d",(int)QThread::currentThreadId()); 
    this->sleep(3); 
    static QString number; 
    QString temp; 
    number += temp.setNum(a); 
    emit signalGUI(number); 
} 
साथ moveToThread का प्रयोग होता है

उत्तर

35

Signals and slots across threads पर एक नज़र डालें। यदि आप हमेशा कार्यकर्ता थ्रेड के साथ संवाद करने के लिए सिग्नल और स्लॉट का उपयोग करते हैं, तो क्यूटी आपके लिए आवश्यक होने पर आपके लिए टॉट थ्रेड को संभालती है और आपने सही कनेक्शन का उपयोग किया है।

संपादित करें: मुझे लगता है कि आलेख के लेखक को उनकी समस्या दिखाई दे रही थी क्योंकि वह वास्तव में थ्रेड वास्तव में निर्मित होने से पहले कन्स्ट्रक्टर में शुरुआत कर रहा था। दूसरे शब्दों में, तीसरे पक्ष के कोड को अंधेरे पर भरोसा न करें।

संपादित करें: अपनी टिप्पणी के जवाब में, Mandelbrot उदाहरण में, देखने के MandelbrotWidget Class Implementation शीर्षक के अंतर्गत:

पंक्तिबद्ध कनेक्शन के साथ, क्यूटी तर्क है कि इतना है कि संकेत करने के लिए पारित किए गए की एक प्रति की दुकान चाहिए कि यह उन्हें बाद में स्लॉट में पास कर सकते हैं। क्यूटी जानता है कि कई सी ++ और क्यूटी प्रकारों की प्रतिलिपि कैसे लेनी है, लेकिन QImage उनमें से एक नहीं है। क्यूईमेज का उपयोग कतारबद्ध कनेक्शन में पैरामीटर के रूप में करने से पहले हमें टेम्पलेट फ़ंक्शन qRegisterMetaType() को कॉल करना होगा।

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

संपादित करें: मैं एक ऐसी ही उदाहरण के साथ चीजों को समझाने की कोशिश करेंगे:

mythread.h:

#ifndef MYTHREAD_H 
#define MYTHREAD_H 

#include <QThread> 
#include <QMutex> 

class MyThread : public QThread 
{ 
    Q_OBJECT 

protected: 
    virtual void run(); 

signals: 
    void signalGUI(QString); 
}; 

#endif // MYTHREAD_H 

mythread.cpp:

#include "mythread.h" 
#include <QString> 

void MyThread::run() 
{ 
    qDebug("Thread id inside run %d",(int)QThread::currentThreadId()); 
    static int run = 0; 
    QString temp = QString("Run: %1").arg(run++); 
    qDebug("String address inside run %p", &temp); 
    emit signalGUI(temp); 
} 

mylineedit।ज

#ifndef MYLINEEDIT_H 
#define MYLINEEDIT_H 

#include <QLineEdit> 

class MyLineEdit : public QLineEdit 
{ 
Q_OBJECT 
public: 
    explicit MyLineEdit(QWidget *parent = 0); 

public slots: 
    void setText(const QString &string); 

}; 

#endif // MYLINEEDIT_H 

mylineedit.cpp

#include "mylineedit.h" 
#include <QThread> 

MyLineEdit::MyLineEdit(QWidget *parent) : 
    QLineEdit(parent) 
{ 
} 

void MyLineEdit::setText(const QString &string) 
{ 
    qDebug("Thread id inside setText %d",(int)QThread::currentThreadId()); 
    qDebug("String address inside setText %p\n", &string); 
    QLineEdit::setText(string); 
} 

main.cpp:

Thread id 1088110320 
Thread id inside run 1093176208 
String address inside run 0x41288350 
Thread id inside setText 1088110320 
String address inside setText 0x974af58

आप देख सकते हैं, रन धागा:

#include <QApplication> 
#include <QPushButton> 
#include <QHBoxLayout> 
#include "mythread.h" 
#include "mylineedit.h" 

//GUI calls a thread to do some job and sub update the text box once it is done 
int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 
    QWidget w; 
    QHBoxLayout * pH = new QHBoxLayout(&w); 
    QPushButton * pushButton = new QPushButton("Run Thread", &w); 
    MyLineEdit * lineEdit = new MyLineEdit(&w); 

    pH->addWidget(pushButton); 
    pH->addWidget(lineEdit); 
    w.show(); 

    MyThread thread; 
    qDebug("Thread id %d",(int)QThread::currentThreadId()); 
    QObject::connect(pushButton,SIGNAL(clicked()),&thread,SLOT(start())) ; 
    QObject::connect(&thread,SIGNAL(signalGUI(const QString&)),lineEdit,SLOT(setText(const QString&))); 
    return a.exec(); 
} 

नमूना उत्पादन बटन क्लिक करने के बाद मुख्य जीयूआई धागे से अलग है। इसके अलावा, भले ही आप क्यूस्ट्रिंग के लिए एक कॉन्स्ट संदर्भ पास करते हैं, क्योंकि यह थ्रेड सीमाओं को पार करता है, यह इसकी प्रतिलिपि बनाता है। I दृढ़ता से आपको Threads and QObject पढ़ने के लिए प्रोत्साहित करता है।

+0

मुझे Qt हैंडलिंग moveToThread के बारे में बताते हुए कोई भी प्रलेखन नहीं देखा गया, मैंने क्यूटी हैंडल सिग्नल स्लॉट कनेक्शन प्रकार के बारे में पढ़ा है जहां ऑब्जेक्ट लाइव है। –

+0

अद्यतन प्रतिक्रिया, मैं थोड़ा सा सरलीकृत हो सकता है, लेकिन ज्यादातर मामलों में यह काम को संभालेगा। –

+0

@Adam आप क्या चाहते हैं "Qt आपके लिए आवश्यक है यदि आपके लिए आवश्यक है और आपने सही कनेक्शन का उपयोग किया है"। उदाहरण के अनुसार 'कनेक्ट (& थ्रेड, सिग्नल (रेंडर इमेज (कॉन्स क्यूमेज और डबल)), यह, एसएलओटी (अपडेट पिक्समैप (कॉन्स क्यूमेज और डबल)); '' थ्रेड' और 'यह' सभी ऑब्जेक्ट्स हैं एक ही धागा लेकिन कनेक्शन कैसे कतार कनेक्शन है? –

3

धागे के बीच एक वस्तु को स्थानांतरित करते समय, आप तय करते हैं कि यह कौन सा ईवेंट लूप है। थ्रेड के अंदर कनेक्शन बनाते समय, सिग्नलिंग कोड सीधे स्लॉट्स में से प्रत्येक को कॉल करता है (उन्हें समाप्त होने का इंतजार करना पड़ता है)। थ्रेड सीमाओं में सिग्नलिंग घटना लूप पर सिग्नल कॉल रखती है, स्लॉट के थ्रेड को तैयार होने पर स्लॉट पर कॉल करने दें।

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

लेख में, मुझे लगता है कि देरी प्रत्यक्ष होने के कारण है, यानी पृष्ठभूमि में संसाधित नहीं किया गया है (लेकिन मैंने केवल पाठ को स्किम किया है)।

+0

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

+0

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

+0

@ e8johan "सुनिश्चित करें कि आपके कार्य पुनर्वित्त हैं" फ़ंक्शन द्वारा आपका मतलब स्लॉट सही था? –

0

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

3
#include <QtGui/QApplication> 
#include <QPushButton> 
#include <QHBoxLayout> 
#include <QLineEdit> 
#include <QString> 
#include "mythread.h" 
//GUI calls a thread to do some job and sub update the text box once it is done 
int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 
    QWidget w; 
    QHBoxLayout * pH = new QHBoxLayout(&w); 
    QPushButton * pushButton = new QPushButton("asdad"); 
    QLineEdit * lineEdit = new QLineEdit("AAA"); 
    pH->addWidget(pushButton); 
    pH->addWidget(lineEdit); 
    w.setLayout(pH); 
    w.show(); 
    MyThread thread; 
    thread.moveToThread(&thread); 
    thread.start(); 
    qDebug("Thread id %d",(int)QThread::currentThreadId()); 
    QObject::connect(pushButton,SIGNAL(clicked()),&thread,SLOT(callRun()),Qt::QueuedConnection) ; 
    QObject::connect(&thread,SIGNAL(signalGUI(QString)),lineEdit,SLOT(setText(QString)),Qt::DirectConnection); 
    return a.exec(); 
} 

#ifndef MYTHREAD_H 
#define MYTHREAD_H 

#include <QThread> 
#include <QMutex> 

class MyThread : public QThread 
{ 
    Q_OBJECT 
public: 
    MyThread(); 
public slots: 
    void callRun(); 
    void run(); 
signals: 
    void signalGUI(QString); 
private: 
    QMutex mutex; 

}; 

#endif // MYTHREAD_H 
#include "mythread.h" 
#include <QDebug> 
#include <QString> 
#include <QMutexLocker> 

MyThread::MyThread() 
{ 
} 
void MyThread::callRun() 
{ 
    QMutexLocker fn_scope(&mutex); 
    static int a = 0; 
    ++a; 
    qDebug("Thread id inside run %d",(int)QThread::currentThreadId()); 
    this->sleep(3); 
    static QString number; 
    QString temp; 
    number += temp.setNum(a); 
    emit signalGUI(number); 

} 
void MyThread::run() 
{ 
    exec(); 
} 

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

+0

शायद यह है एक टाइपो लेकिन आपके 'मुख्य (...)' फ़ंक्शन में आप स्पष्ट रूप से 'Qt :: DirectCon का अनुरोध करते हैं नीक्शन 'और इसमें आपदा की संभावना है, यह देखते हुए कि सिग्नल' माई थ्रेड 'ऑब्जेक्ट से निकलता है और इसलिए, जीयूआई स्पर्श' सेटटेक्स्ट (...) 'स्लॉट मुख्य धागे के अलावा किसी धागे के संदर्भ में निष्पादित हो जाता है । – axxel

8
  1. QThread::start() विधि धागा बनाता है और अपने run() कार्यान्वयन कहता है। यदि आप थ्रेड पर घटनाओं को प्राप्त करना चाहते हैं या सिग्नल प्राप्त करना चाहते हैं तो आपको QThread::exec() के अंदर run() कार्यान्वयन के अंदर कॉल करना होगा। आपको run() को स्पष्ट रूप से कभी भी कॉल नहीं करना चाहिए और आपको run() के बाहर exec() पर कभी भी कॉल नहीं करना चाहिए।

  2. मालिक धागा केवल तभी फर्क पड़ता है जब स्लॉट Qt::DirectConnection के अलावा कनेक्शन प्रकार के साथ सिग्नल से जुड़ा होता है। फिर क्यूटी यह सुनिश्चित करेगा कि स्लॉट मालिक थ्रेड पर चलता है, लेकिन इसके लिए मालिक थ्रेड QThread::exec() के साथ एक ईवेंट लूप चला रहा है। इस मामले में myObj.moveToThread(myThread) पर कॉल करना सुनिश्चित होगा कि myObj स्लॉट myThread पर चलते हैं।

  3. थ्रेड ऑब्जेक्ट उस थ्रेड से संबंधित है जहां इसे बनाया गया था, न कि उस थ्रेड पर जो यह प्रबंधित करता है (और जहां रन विधि चलती है)। तो जब आप किसी थ्रेड ऑब्जेक्ट के स्लॉट पर सिग्नल कनेक्ट करते हैं, तो वह स्लॉट थ्रेड में चलाएगा जहां थ्रेड ऑब्जेक्ट बनाया गया था जब तक कि आप moveToThread() पर कॉल न करें।

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