私はPythonインタプリタを埋め込みたいC++/Qtアプリケーションを持っています。私はPythonをQThreadから呼びたいと思っていますが、PyGILState_Ensure()を呼び出してグローバルインタープリタロック(GIL)を取得しようとすると、デッドロックが発生します。QThreadがPyGILState_Ensure()経由でPython GILを取得しようとするとデッドロックが発生する
私はhere与えられた勧告に従った、以下最小限とストレートな例を提供します:
//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内からスレッドを作成することには興味がありませんのでご注意ください。私はちょうどQThreadから特定のPythonスクリプトを直接前方に呼びたいと思う。
- 私はもうsimilarquestionsを読んだことがありますが、そこには微妙な違いがあると感じていましたが、そこにある回答から問題を解決できませんでした。また、
PyEval_InitThreads()
に電話する推奨事項が混乱しています。Python/C API documentationが正しく理解されていれば、それは必要ないはずです。
:ここ
は、問題を解決
main.cpp
の更新版ですか?アプリケーションがスタックしているときは、デバッガを使用してすべてのスレッドがスタックを呼び出すかどうかを調べます。 –PyGILState_Ensure()が呼び出された行でデバッガを停止し、そこから1行進むとプログラムがロックアップします。私。スレッドはPyGILState_Ensure()内のどこかでスタックします。 – andreasdr