Punto muerto cuando QThread intenta adquirir Python GIL a través de PyGILState_Ensure ()
Tengo una aplicación C ++ / Qt en la que quiero incrustar el intérprete de Python. Quiero llamar a Python desde un QThread, pero obtengo un punto muerto en la línea donde llamo PyGILState_Ensure () para intentar adquirir el bloqueo global del intérprete (GIL).
Proporcionaré un ejemplo mínimo y directo a continuación, que sigue las recomendaciones dadasaquí:
//main.cpp:
#include <QCoreApplication>
#include <QThread>
#include "Worker.h"
void startThread()
{
QThread* thread = new QThread;
Worker* worker = new Worker();
worker->moveToThread(thread);
QObject::connect(thread, SIGNAL(started()), worker, SLOT(process()));
QObject::connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
QObject::connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Py_Initialize();
startThread();
Py_FinalizeEx();
return a.exec();
}
//Worker.h:
#ifndef WORKER_H
#define WORKER_H
#include <QObject>
#include "Python.h"
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr) : QObject(parent) {}
Q_SIGNALS:
void finished();
public Q_SLOTS:
void process()
{
qDebug("Calling Python");
PyGILState_STATE gstate = PyGILState_Ensure();
PyRun_SimpleString("print(\"hello\")");
PyGILState_Release(gstate);
qDebug("Done calling Python");
Q_EMIT finished();
}
};
#endif // WORKER_H
Algunos comentarios adicionales:
Nota: el archivo .pro contiene la líneaCONFIG += no_keywords
, para evitar conflictos de nombres con el encabezado de Python.Cabe señalar que mientras el hilo detiene la ejecución en la llamada a PyGILState_Ensure (), el hilo principal continúa sin inhibiciones. Si cambioreturn a.exec();
areturn 0;
, el programa saldrá. (Entonces quizás el punto muerto sea el término incorrecto para usar).Tenga en cuenta que no estoy interesado en crear hilos desde Python. Solo quiero llamar directamente a un script de Python dado desde un QThread.He leído otrosimilar preguntas, pero consideró que los casos considerados allí son sutilmente diferentes, y no he podido resolver mi problema con las respuestas dadas allí. Además, estoy confundido por las recomendaciones para llamarPyEval_InitThreads()
, que si entiendo elDocumentación de API Python / C correctamente, no debería ser necesario.