使用线程调用Py_Finalize时出现AssertionError(仅3.X) [英] AssertionError (3.X only) when calling Py_Finalize with threads
问题描述
当我从与执行python调用不同的C线程中调用C-API的Py_Finalize()时,收到错误输出.
I'm getting an error output when I call the C-API's Py_Finalize() from a different C-thread than I made a python call on.
我看到的错误是:
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中,完全相同的代码没有任何问题.
This only happens in Python 3.X (tested with 3.4.2), in Python 2.7 the exact same code doesn't have any issues.
这是一个最小的示例,它显示了使用C线程时发生的情况,但并非所有事件都发生在单个c线程中时发生的情况:
Here's a minimal example that shows it happening when a C-thread is used, but not when everything happens on a single c-thread:
#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--
main中的basic()/with_thread()调用的顺序无关紧要,我什至可以多次包含这些行而没有任何影响,每个with_thread()调用都会导致错误输出.
The order of the basic()/with_thread() calls in main does not matter, I can even include those lines multiple times with no affect, each with_thread() call results in the error output.
将threadState设为全局,然后将exec更改为:
Making the threadState global, then changing exec to:
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像原始示例那样更加孤立地有什么见解?
causes the error to go away, however then I have a global value I need to coordinate between the users of my library (in my actual code, the exec() function could be written by anybody and I have a lot more initialization stuff that I run). Any insights on how to make the GIL grabbing more isolated like the original example while keeping thread compatibility?
推荐答案
尝试添加
Py_DECREF(PyImport_ImportModule("threading"));
之后
PyEval_InitThreads();
这篇关于使用线程调用Py_Finalize时出现AssertionError(仅3.X)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!