У меня есть приложение 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.
- Я читал другие подобные questions, но чувствовал, что рассмотренные там случаи немного отличаются, и я не смог решить свою проблему из даны там ответы. Кроме того, меня смущают рекомендации вызывать
PyEval_InitThreads()
, что, если я понимаю документация по Python/C API не нужна.