Question

Dans mon application, il existe un thread principal et un thread de travail ( QThread ).
Depuis le thread principal, j'aimerais invoquer une méthode de mon thread de travail et l'exécuter dans le contexte du thread.

J'ai essayé d'utiliser QMetaObject :: invokeMethod et lui ai donné l'option QueuedConnection , mais cela ne fonctionne pas.
J'ai également essayé d'émettre des signaux à partir du thread principal (qui est connecté au logement du thread de travail), mais cela a également échoué.

Voici un extrait de ce que j'ai essayé à peu près:

class Worker : public QThread
{
    Q_OBJECT

public:
    Worker() { }

    void run() 
    { 
        qDebug() << "new thread id " << QThread::currentThreadId(); 
        exec(); 
    }

public slots:
    void doWork()
    {
        qDebug() << "executing thread id - " << QThread::currentThreadId();
    }
};

Utilisation de la méthode QMetaObject:

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

    qDebug() << "main thread id - " << QThread::currentThreadId();

    Worker worker;
    worker.start();

    QMetaObject::invokeMethod(&worker, "doWork", Qt::QueuedConnection);

    return a.exec();
}

Utilisation de la voie du signal:

class Dummy : public QObject
{
    Q_OBJECT

public:
    Dummy() { }

public slots:
    void askWork() { emit work(); }

signals:
    void work();
};

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

    qDebug() << "main thread id - " << QThread::currentThreadId();

    Worker worker;
    worker.start();

    Dummy dummy;
    QObject::connect(&dummy, SIGNAL(work()), &worker, SLOT(doWork()), Qt::QueuedConnection);

    QTimer::singleShot(1000, &dummy, SLOT(askWork()));

    return a.exec();
}

Dans les deux cas, l'id du thread principal est imprimé dans QThread doWork .

En outre, j’ai envisagé de mettre en place un simple producteur-consommateur, mais si cela fonctionne, n’y a-t-il aucune raison de ne pas le faire de cette façon?

Était-ce utile?

La solution

Le problème était que le récepteur (le QThread) vivait dans le thread principal et que la boucle d'événements du thread principal était celle qui exécutait l'emplacement.

à partir de la documentation de Qt:

  

Avec les connexions en file d'attente, l'emplacement est appelé lorsque le contrôle retourne à la boucle d'événements du fil auquel appartient l'objet. L'emplacement est exécuté dans le thread où réside l'objet récepteur.

La solution que j’ai trouvée jusqu’à présent consistait donc à créer un objet à l’intérieur du run () du thread et à utiliser ses slots. De cette façon, le propriétaire du destinataire est le thread, puis l'emplacement est appelé dans le contexte des threads.

Autres conseils

Cet exemple montre comment diviser la classe Worker pour qu'elle fonctionne comme vous le souhaitez. Vous devez également mettre à disposition une référence ou un pointeur sur l'instance de Worker pour pouvoir vous connecter à l'emplacement.

class Worker : public QObject
{
    Q_OBJECT

public:
    Worker() { }

public slots:
    void doWork()
    {
        qDebug() << "executing thread id - " << QThread::currentThreadId();
    }
};

class WorkerThread : public QThread
{
    Q_OBJECT

public:
    void run()
    {
        qDebug() << "new thread id " << QThread::currentThreadId(); 
        Worker worker;
        exec();
    }
};

Pour l’exemple simple producteur-consommateur, consultez l’entrée de blog de Bradley T. Hughes Treading sans le mal de tête .

Le travailleur est créé dans le thread principal et, par conséquent, ses événements sont traités dans le thread principal. Vous devez déplacer le travailleur sur son propre fil:

Worker worker;
worker.moveToThread(&worker);
worker.start();

Qt sait maintenant que worker réside dans le nouveau thread et mettra les événements en file d'attente dans cette boucle d'événements.

Il semble que votre thread de travail se termine avant même que vous puissiez invoquer une fonction ou lui envoyer un signal.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top