Я пытаюсь подключиться к устаревшему многопотоковому приложению Python из разрабатываемого нового кода C ++. Кажется, я не могу заставить вызовы C ++ в Python работать надежно, если код Python запустил поток. В псевдокоде я пытаюсь заставить работать:
- Бинарный файл C ++ запускается
- Бинарный файл C ++ инициализирует среду Python и импортирует необходимые модули.
- Python запускает один или несколько потоков
- На каком-то этапе позже C ++ выполняет один или несколько вызовов функций Python.
- ...
- Программа на C ++ очищает среду Python и завершает работу.
Код, который у меня есть до сих пор, успешно вызывает функцию Python несколько раз из C ++, но дает сбой при выходе, а также единственный поток, созданный в Python, кажется, останавливается до тех пор, пока не будет завершена программа на C ++.
Текущие вызовы, которые я делаю для настройки среды Python:
// Initialize Python environment
Py_Initialize();
// Initialize threading and acquire Python GIL
PyEval_InitThreads();
PyThreadState * mainThreadState = NULL;
// save a pointer to the main PyThreadState object
mainThreadState = PyThreadState_Get();
// release the lock
PyEval_ReleaseLock();
// get the global lock
PyEval_AcquireLock();
// get a reference to the PyInterpreterState
PyInterpreterState* mainInterpreterState = mainThreadState->interp;
// create a thread state object for this thread
PyThreadState* myThreadState = PyThreadState_New(mainInterpreterState);
// free the lock
PyEval_ReleaseLock();
PySys_SetArgv(argc, argv);
Затем функция Python вызывается несколько раз следующим образом:
// grab the global interpreter lock
PyEval_AcquireLock();
// swap in my thread state
PyThreadState_Swap(myThreadState);
PyObject* pMod = PyImport_ImportModule(moduleName.c_str());
PyObject* pfn = PyObject_GetAttrString(pMod, fnName.c_str());
// Create the data structure to pass the single C string
PyObject* pargs = Py_BuildValue("(s)", arg.c_str());
PyObject* result = PyEval_CallObject(pfn, pargs);
Py_DECREF(pargs);
Py_DECREF(pfn);
Py_DECREF(pMod);
// clear the thread state
PyThreadState_Swap(NULL);
// release our hold on the global interpreter
PyEval_ReleaseLock();
Код однократной очистки, вызываемый, когда приложение C ++ готовится к завершению, имеет следующий вид:
PyEval_AcquireLock();
Py_Finalize();
Было бы здорово, если бы кто-нибудь мог указать мне на какой-то образец кода, который делает то, что я пытаюсь достичь, или мог бы указать, что я делаю неправильно в вышеуказанных шагах?