которая решает проблему:
я есть приложение C ++ / Qt, в которое я хочу встроить интерпретатор Python. Я хочу вызвать Python из QThread, но я получаю тупик в строке, где я вызываю PyGILState_Ensure (), чтобы попытаться получить глобальную блокировку интерпретатора (GIL).
Я приведу минимальный и простой пример ниже, который следует рекомендациям, даннымВот:
//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
Некоторые дополнительные комментарии:
Примечание. Файл .pro содержит строкуCONFIG += no_keywords
, чтобы избежать конфликтов имен с заголовком Python.Следует отметить, что хотя поток останавливает выполнение при вызове PyGILState_Ensure (), основной поток продолжает не блокироваться. Если я изменюreturn a.exec();
вreturn 0;
, программа выйдет. (Так что, возможно, тупик - неправильный термин.)Обратите внимание, что я не заинтересован в создании потоков внутри Python. Я просто хочу прямо вызвать данный скрипт Python из QThread.Я читал другиеаналогичный вопросов, но чувствовал, что рассматриваемые там случаи немного отличаются, и я не смог решить мою проблему из ответов, данных там. Также меня смущают рекомендации звонитьPyEval_InitThreads()
что если я понимаюДокументация по API Python / C правильно, не нужно