python — AssertionError (только 3.X) при вызове Py_Finalize с потоками

Я получаю сообщение об ошибке, когда я вызываю Py_Finalize () C-API из другого C-потока, чем я сделал вызов Python.

Я вижу ошибку:

Exception ignored in: <module 'threading' from 'C:\\Python34-32\\Lib\\threading.py'>
Traceback (most recent call last):
File "C:\Python34-32\Lib\threading.py", line 1289, in _shutdown
assert tlock.locked()
AssertionError:

Это происходит только в Python 3.X (протестировано с 3.4.2), в Python 2.7 точно такой же код не имеет проблем.

Вот минимальный пример, который показывает, что это происходит при использовании C-потока, но не когда все происходит в одном C-потоке:

#include <iostream>
#include <fstream>
#include <thread>
#include <cassert>

#include <Python.h>

void make_file()
{
std::fstream file("my_test.py", std::ios::out);
file <<
"import threading\n"   <<
"def my_function():\n" <<
"    pass\n"             ;
file.close();
}

void exec()
{
PyGILState_STATE gstate = PyGILState_Ensure();
PyObject* pdict = PyDict_New();
PyDict_SetItemString(pdict, "__builtins__", PyEval_GetBuiltins());

PyRun_String("import my_test", Py_file_input, pdict, pdict);
PyRun_String("my_test.my_function()", Py_file_input, pdict, pdict);
assert(!PyErr_Occurred());
PyGILState_Release(gstate);
}

void basic()
{
std::cout << "--Starting Basic--" << std::endl;

Py_Initialize();
PyEval_InitThreads();
PyThreadState* threadState = PyEval_SaveThread();

exec();

PyEval_RestoreThread(threadState);
Py_Finalize();

std::cout << "--Basic Complete--" << std::endl;
}

void with_thread()
{
std::cout << "--Starting With Thread--" << std::endl;

Py_Initialize();
PyEval_InitThreads();
PyThreadState* threadState = PyEval_SaveThread();

std::thread t(exec);
t.join();

PyEval_RestoreThread(threadState);
Py_Finalize();

std::cout << "--With Thread Complete--" << std::endl;
}

int main(int argc, char* argv[])
{
make_file();
basic();
with_thread();

return 0;
}

выход

--Starting Basic--
--Basic Complete--
--Starting With Thread--
Exception ignored in: <module 'threading' from 'C:\\Python34-32\\Lib\\threading.py'>
Traceback (most recent call last):
File "C:\Python34-32\Lib\threading.py", line 1289, in _shutdown
assert tlock.locked()
AssertionError:
--With Thread Complete--

Порядок вызовов basic () / with_thread () в main не имеет значения, я даже могу включать эти строки несколько раз без каких-либо последствий, каждый вызов with_thread () приводит к выводу ошибки.

Редактировать :

Делая threadState глобальным, затем изменяя exec на:

void exec()
{
//PyGILState_STATE gstate = PyGILState_Ensure();
PyEval_RestoreThread(threadState);
PyObject* pdict = PyDict_New();
PyDict_SetItemString(pdict, "__builtins__", PyEval_GetBuiltins());

PyRun_String("import my_test", Py_file_input, pdict, pdict);
PyRun_String("my_test.my_function()", Py_file_input, pdict, pdict);
assert(!PyErr_Occurred());
//PyGILState_Release(gstate);
threadState = PyEval_SaveThread();
}

приводит к исчезновению ошибки, однако тогда у меня есть глобальное значение, которое мне нужно координировать между пользователями моей библиотеки (в моем реальном коде функция exec () может быть написана кем угодно, и у меня есть гораздо больше вещей для инициализации, которые я бежать). Есть какие-нибудь идеи о том, как сделать захват GIL более изолированным, как в оригинальном примере, сохраняя совместимость потоков?

1

Решение

Попробуйте, добавив

Py_DECREF(PyImport_ImportModule("threading"));

после

PyEval_InitThreads();
2

Другие решения


По вопросам рекламы [email protected]