2017-08-10 6 views
0

J'ai un thread principal pour l'interface graphique, dans lequel est exécuté l'objet MainWindow, dans son constructeur, je crée un nouvel objet de travail et un objet QThread et je déplace le travailleur vers le fil , le problème est que lors de l'impression leurs papiers d'identité, ils sont les mêmes:QThread moveToThread ne fonctionne pas

mainwindow.cpp

MainWindow::MainWindow(QWidget *parent) : 
    QMainWindow(parent), 
    ui(new Ui::MainWindow) 
{ 
    std::cout<<"MAIN_ID "<< QThread::currentThreadId()<<std::endl; 
    QThread *t_pc = new QThread; 
    worker *pc_w; 
    pc_w = new pc_worker(); 
    pc_w->moveToThread(t_pc); 
    t_pc->start(); 
    pc_w->initialize(); 
    // ... 
} 

worker.cpp

worker::worker(QObject *parent) : QObject(parent) { 

} 

void worker::initialize() { 
    std::cout << "INITIALIZE " << QThread::currentThreadId() << std::endl; 
} 

je reçois:

MAIN_ID 0x7f4009ccb780 
INITIALIZE 0x7f4009ccb780 

Quel est le problème?

+0

Mais lorsque la classe worker est appelée via connect SLOT/SIGNAL, les ID imprimés sont différents –

+2

Lorsque vous appelez une fonction directement, elle s'exécute dans le thread à partir duquel vous l'appelez. – thuga

+0

Définissez initialize() comme emplacement et émettez un signal à partir de MainWindow.Connectez-les comme ceci: connect (this, SIGNAL (signal_initialize()), pc_w, SLOT (initialize()), Qt :: QueuedConnection); –

Répondre

0

Essayez d'utiliser invokeMethod au lieu d'appeler diretly pc_w->initialize(), .: par exemple

QMetaObject::invokeMethod(pc_w, "initialize", Qt::QueuedConnection); 

Votre méthode initialize() doit être SLOT ou un signal dans ce cas.

1

Réponse: moveToThreadfait ne fonctionne pas comme vous l'attendiez.

Il semblerait qu'après avoir appelé pc_w->moveToThread(t_pc), vous vous attendiez à ce que toutes les fonctions membres de pc_w soient appelées en t_pc maintenant. Cependant, ce n'est pas ce que fait moveToThread().

Le but de moveToThread() est de changer QObject "affinité de fil" ou en d'autres termes fil où un objet vit. Mais sur le niveau de base tout ce qu'il vous donne est juste la garantie que tous les emplacements de l'objet connecté à un signal via Qt::QueuedConnection sera appelé (exécuter) dans ce fil particulier.

Les fonctions membres s'exécutent toujours dans le thread à partir duquel vous les appelez. Dans votre cas, vous appelez initialize() à partir du fil de l'interface graphique, alors QThread::currentThreadId() vous donne l'ID de ce fil de discussion.

Je recommande vraiment de lire le document officiel sur thread affinity et this article sur les boucles d'événements de threads.

QThread* thread = new QThread; 
Worker* worker = new Worker; 

// Uses Qt::AutoConnection (default) 
// which will be transalted into Qt::QueuedConnection 
QObject::connect(thread, &QThread::started, worker, &Worker::initialize); 

std::cout<<"MAIN_ID "<< QThread::currentThreadId()<<std::endl; 

worker->moveToThread(thread); 
thread->start(); 

Sortie:

MAIN_ID 0000000000003E5C 
INITIALIZE 0000000000003DAC 

La solution trivelt proposé met artificiellement événement "appel initialize()" dans la boucle d'événements de fil pour atteindre le même effet. Cependant, il n'effectue aucune vérification à la compilation ("initialize" est spécifié en tant que chaîne).