2010-10-12 2 views
2

depuis un certain temps, je suis fiddly maintenant pour obtenir une énorme action de vidange temps/cputime derrière une interface utilisateur répondante. Malheureusement, je n'arrive pas à le faire fonctionner et "je pense" le problème est que le slot n'est pas traité dans le worker QThread mais le thread graphique. Les ThreadID diffèrent comme prévu cependant.QThread, enfilé, rly?

Je l'ai déjà lu http://doc.trolltech.com/4.6/threads-qobject.html et utilisé recherche googel et SO mais rien qui m'a vraiment aidé. Probablement son quelque chose de têtu que je ne vois pas.

Ci-dessous mon code dénudation (Note: un .png nommé "dummy1024x1024.png" est nécessaire dans le même dossier que le fichier binaire):

main.cpp

#include <QtGui> 
#include "dummy.h" 

int main(int argc, char** argv) 
{ 
    QApplication app(argc, argv); 
    Dummy d(NULL); 
    d.show(); 
    qDebug() << "App thread " << QThread::currentThreadId(); 
    return app.exec(); 
} 

factice . h

#ifndef DUMMY_H 
#define DUMMY_H 

#include <QWidget> 
#include <QVBoxLayout> 
#include <QPushButton> 

#include "workerthread.h" 

class Dummy : public QWidget 
{ 
Q_OBJECT 
public: 
    explicit Dummy(QWidget *parent = 0); 
    virtual ~Dummy(); 
private: 
    QVBoxLayout* m_layout; 
    QPushButton* m_dummy[3]; 
    QPushButton* m_shootcalc; 
    WorkerThread* m_work; 
signals: 

public slots: 

}; 

#endif // DUMMY_H 

dummy.cpp

#include "dummy.h" 

Dummy::Dummy(QWidget *parent) : 
    QWidget(parent) 
{ 
    m_work = new WorkerThread(this); 
    m_work->start(); 

    m_shootcalc = new QPushButton("Calc!", this); 
    connect(m_shootcalc, SIGNAL(clicked()), m_work, SLOT(expensiveCalc()), Qt::QueuedConnection); 

    m_dummy[0] = new QPushButton("Dummy [0]", this); 
    m_dummy[1] = new QPushButton("Dummy [1]", this); 
    m_dummy[2] = new QPushButton("Dummy [2]", this); 

    m_layout = new QVBoxLayout(this); 
    m_layout->addWidget(m_shootcalc); 
    m_layout->addWidget(m_dummy[0]); 
    m_layout->addWidget(m_dummy[1]); 
    m_layout->addWidget(m_dummy[2]); 
    setLayout(m_layout); 
} 


Dummy::~Dummy() 
{ 
    m_work->quit(); 
    m_work->wait(); 
    m_work->deleteLater(); 
    m_work = NULL; 
} 

workerthread.h

#ifndef WORKERTHREAD_H 
#define WORKERTHREAD_H 

#include <QThread> 
#include <QPixmap> 
#include <QDebug> 

class WorkerThread : public QThread 
{ 
Q_OBJECT 
public: 
    explicit WorkerThread(QObject *parent = 0); 
protected: 
    virtual void run(); 
signals: 

public slots: 
    void expensiveCalc(); 
}; 

#endif // WORKERTHREAD_H 

workerthread.cpp

#include "workerthread.h" 

WorkerThread::WorkerThread(QObject *parent) : 
    QThread(parent) 
{ 
} 


void WorkerThread::run() 
{ 
    qDebug() << "Thread start << " << QThread::currentThreadId(); 
    exec(); 
    qDebug() << "Thread stop << " << QThread::currentThreadId(); 
} 

void WorkerThread::expensiveCalc() 
{ 
    qDebug() << "start pixie loading.... " << QThread::currentThreadId(); 
    QPixmap* pixies[16384]; 
    for (int i=0; i<16384; ++i) 
    { 
     pixies[i] = new QPixmap("./dummy1024x1024.png"); 
     if (i>0) 
      delete pixies[i-1]; 
     msleep(1); 
    } 
    delete pixies[16384-1]; 

    qDebug() << "loaded pixies " << QThread::currentThreadId(); 
    qDebug() << ""; 
    qDebug() << ""; 
    qDebug() << ""; 
    qDebug() << ""; 
} 

Merci pour toute aide/conseil/réponse

+1

il y avait un article dans le "Linux Magazin" allemand, à propos de ce problème. Et il y a du code disponible sur github pour les workerthreads qui fonctionnent correctement avec les signaux/slots. Voir ici: http://github.com/picaschaf/Qt-Worker-Thread Cela pourrait être ce que vous cherchez. – smerlin

+1

Merci pour cette information, je lis habituellement le LinuxMagazine mais il me semble que j'ai raté ça. J'ai fait le code ci-dessus basé sur ce que la documentation Qt et les exemples m'ont dit. Malheureusement, la documentation QThread est l'une des pires parties du Qt Doc. – drahnr

Répondre

5

L'utilisation correcte de QThread est une commune problème parmi Qt u sers. Ce blog post chez Qt Labs l'explique bien.

En résumé, vous devez et non sous-classe QThread pour contenir le code que vous souhaitez exécuter dans ce thread. Vous devez placer votre code dans une sous-classe QObject, l'instancier et utiliser un QObject::moveToThread pour déplacer votre objet dans le contexte QThread afin que le traitement se produise dans le contexte de ce QThread. Vous pouvez alors avoir des sous-classes dans votre sous-classe QObject qui peuvent être connectées en toute sécurité à un autre thread mais fonctionneront dans le contexte que vous attendez. Certains peuvent soutenir que sous-classement QThread devrait être bien si vous pouvez facilement adapter ce que vous voulez faire à l'intérieur de la méthode run() et ne nécessitent pas beaucoup (ou aucune) interaction externe, mais même dans ce cas simple, je serais favorable à un séparé classe pour une meilleure encapsulation.

+3

et de décrire le problème réel: le qobject QThread lui-même vit dans le thread principal, pas dans le fil lui-même représente (!). La séparation décrite par Arnold devrait le rendre plus clair. –

+0

Merci, oui, l'objet QThread "vit" dans le thread principal, donc les signaux à lui sont traités dans la boucle d'événement principal qui est ce que l'OP voit. –

+0

il y avait un article dans l'allemand "Linux Magazin", à propos de ce problème. Et il y a du code disponible sur github pour les workerthreads qui fonctionnent correctement avec les signaux/slots. Voir ici: http://github.com/picaschaf/Qt-Worker-Thread Cela pourrait être ce que vous cherchez. – smerlin

Questions connexes