Invocación de métodos en el contexto de QThread
-
06-07-2019 - |
Pregunta
En mi aplicación está el hilo principal y un hilo de trabajo ( QThread
).
Desde el hilo principal me gustaría invocar un método de mi hilo de trabajo y hacer que se ejecute en el contexto del hilo.
He intentado usar QMetaObject :: invokeMethod
y le doy la opción QueuedConnection
pero no funciona.
También intenté emitir señales desde el subproceso principal (que está conectado a la ranura del subproceso de trabajo) pero eso también falló.
Aquí hay un fragmento de aproximadamente lo que probé:
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();
}
};
Usando la forma 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();
}
Usando la señal:
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();
}
En ambos sentidos, la identificación del hilo principal se imprime en el QThread
doWork
.
Además, pensé en implementar un simple productor-consumidor, pero si esto funciona, ¿hay alguna razón para no hacerlo de esta manera?
Solución
El problema era que el receptor (el QThread) 'vive' en el hilo principal y, por lo tanto, el bucle de eventos del hilo principal es el que ejecuta la ranura.
de los documentos de Qt:
Con las conexiones en cola, la ranura se invoca cuando el control vuelve al bucle de eventos del hilo al que pertenece el objeto. La ranura se ejecuta en el hilo donde vive el objeto receptor.
Entonces, la solución que encontré hasta ahora fue crear un objeto dentro de la ejecución del hilo () y usar sus ranuras en su lugar. De esta forma, el propietario del receptor es el hilo y luego se llama a la ranura en el contexto de hilos.
Otros consejos
Este ejemplo muestra cómo puede dividir la clase Worker para que funcione como desee. También debe poner a disposición una referencia o puntero a la instancia de Worker para poder conectarse a la ranura.
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();
}
};
Para el ejemplo simple productor-consumidor, eche un vistazo a la entrada del blog de Bradley T. Hughes Pisando sin dolor de cabeza .
El trabajador se crea en el hilo principal y, por lo tanto, sus eventos se procesan en el hilo principal. Debe mover al trabajador a su propio hilo:
Worker worker;
worker.moveToThread(&worker);
worker.start();
Ahora Qt sabe que trabajador
vive en el nuevo hilo y pondrá en cola los eventos en ese bucle de eventos.
Parece que su hilo de trabajo se completa antes de que pueda invocar cualquier función o enviarle una señal.