2017-03-31 1 views
1

Je pense à la manière de transmettre les données de résultat d'un thread de travail au client sans les copier. Le travailleur vit dans un autre thread et BigData hérite de QObject. Mon idée est de changer la propriété des données:QThread transmet les données de résultat à MainThread

class Worker: public QObject 
{ 
    Q_OBJECT 
public: 
    explicit Worker(QObject *parent = 0): QObject(parent); 
signals: 
    void resultReady(BigData *data); 
public slots: 
    void doWork() { 
     BigData *data = new BigData(this); // alloc new Data 
     while (!dataReady) { 
      ... // appending data 
     } 
     // Data ready 
     // clearing ownership 
     data->setParent(NULL); // data can't be moved to another thread with parent 
     data->moveToThread(NULL); 
     emit resultReady(data); 
    } 
}; 

void MainWindow::handleResult(BigData *data) 
{ 
    if (currentData_) { 
     delete currentData_; 
    } 
    data->setParent(this); // set new ownership 

    // works only if data's thread is NULL 
    data->moveToThread(QApplication::instance()->thread()); 
    currentData_ = data; 
} 

Est-ce que ça a l'air bien? Ou y at-il une façon plus appropriée de le faire?

+0

Y a-t-il une raison pour que la classe 'BigData' hérite de' QObject'? A-t-il ses propres signaux/slots? – Mike

+0

Non, j'utilise simplement QObject car la destruction automatique de BigData sur la destruction de ses parents est très pratique. – Sorcerer

Répondre

2

Habituellement, vous utilisez moveToThread() pour pousser un objet d'un fil à l'autre. Cela signifie que, au lieu de faire data->moveToThread(NULL); dans votre emplacement doWork(), vous pouvez écrire data->moveToThread(QApplication::instance()->thread()); pour éviter de définir l'affinité de thread à NULL puis de modifier cela à partir du thread principal. Mais après avoir déplacé l'instance BigData au thread principal, Sachez que vous avez touché le QObject à partir du thread de travail. Une autre chose à noter à propos est que le déplacement d'un QObject et-vient entre les fils peut causer des effets secondaires, de la docs:

Notez que tous les compteurs actifs de l'objet seront remis à zéro. Les minuteurs sont d'abord arrêtés dans le thread en cours et redémarrés (avec le même intervalle) dans le targetThread. Par conséquent, le déplacement constant d'un objet entre les threads peut retarder indéfiniment les événements de temporisation.

Inherting QObject juste pour le but de la gestion de la mémoire est un surpuissant. QObject fournit much more stuff (Capacités d'introspection, propriétés dynamiques, signaux/slots, affinité de threads, traitement d'événements, internationalisation ...) dont vous n'avez pas vraiment besoin ici. Si vous êtes intéressé uniquement par la gestion de la mémoire, Qt et the C++ standard library disposent de pointeurs intelligents qui peuvent implémenter la gestion de la durée de vie de l'objet par une sémantique de propriété unique ou de propriété partagée.

Jetez un oeil à this answer pour un exemple de modèle qui décharge le chargement de données au pool de threads global et affiche ces données dans la vue dès qu'elles sont prêtes. Notez que le modèle hérite QObject (car QAbstractItemModel hérite de QObject, car il utilise des signaux/intervalles pour informer l'affichage des modifications de données), mais il n'y a aucune raison pour que la structure de données qui détient effectivement les données hérite QObject. . .

+0

Je pensais aussi à des pointeurs intelligents. Merci pour la réponse – Sorcerer

+0

@Sorcerer, une autre chose à noter est que votre code a actuellement une condition de course (qui vient d'attirer mon attention). Que faire si la fenêtre est détruite avant l'appel de 'handleResult'? puisque 'handleResult' est actuellement l'endroit où vous revendiquez la propriété de votre objet' BigData', votre objet 'BigData' sera divulgué. Encore une fois, vous devriez changer votre conception comme mentionné dans ma réponse. . . – Mike