Python3 C++ 模块 - 异常 - GIL 未持有
Posted
技术标签:
【中文标题】Python3 C++ 模块 - 异常 - GIL 未持有【英文标题】:Python3 C++ Module - Exception - GIL not held 【发布时间】:2021-07-04 13:13:27 【问题描述】:我已经创建了一个我遇到的问题的最小复制,试图创建一个基于 C++ 的 Python3 模块。构建环境为 CMake、Visual Studio Pro 2019、WinSDK 10.0.18362、Python 3.9.4。执行时:
python3 -c "import pymod"
我将在具有 NULL 访问权限的发布模式下遇到异常。在调试 Python 时,我得到了更多信息。
我的 CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(pymod_minimal_repo_example)
find_package(Python3 COMPONENTS Interpreter Development)
add_library(pymod SHARED)
target_sources(pymod PRIVATE pymodmodule.cpp)
set_target_properties(pymod PROPERTIES SUFFIX ".pyd")
target_compile_options(pymod PRIVATE /Zi)
target_link_options(pymod PRIVATE /DEBUG:FULL)
target_link_libraries(pymod PRIVATE $Python3_LIBRARIES)
target_include_directories(pymod PRIVATE $Python3_INCLUDE_DIRS)
在此 python 参考之后:https://docs.python.org/3.9/extending/extending.html#a-simple-example 我创建了以下内容:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
static struct PyModuleDef pymodmodule =
PyModuleDef_HEAD_INIT, // m_base
"pymod", // m_name
NULL, // m_doc
-1, // m_size - submod not support must be static struct
NULL, // m_methods - no functions present
NULL, // m_slots - must be NULL
NULL, // m_traverse - not needed
NULL, // m_clear - not needed
NULL // m_free - not needed
;
PyMODINIT_FUNC PyInit_pymod(void)
return PyModule_Create(&pymodmodule);
它是一个功能无效的模块,它什么都不做,但仍应运行。请注意,定义了 m_methods 会产生同样的失败。
发生故障时,向控制台输出以下内容:
E:\projects\pymod\build\Debug>python -c "import pymod"
Fatal Python error: _PyInterpreterState_GET: the function must be called with the GIL held, but the GIL is released (the current Python thread state is NULL)
Python runtime state: unknown
WinDbg jit 调试器随后会发现问题。部分调用堆栈显示我的 PyInit_pymod 被调用,并且在创建 python 模块时,它级联失败:
0:000> k
# Child-SP RetAddr Call Site
00 000000dc`abfed4a8 00007fff`71d51385 KERNELBASE!wil::details::DebugBreak+0x2
01 000000dc`abfed4b0 00007fff`71d511a8 python39_d!fatal_error_exit+0x15 [D:\a\1\s\Python\pylifecycle.c @ 2201]
02 000000dc`abfed4e0 00007fff`71d4ea98 python39_d!fatal_error+0x1b8 [D:\a\1\s\Python\pylifecycle.c @ 2286]
03 000000dc`abfed540 00007fff`71cbe730 python39_d!_Py_FatalErrorFunc+0x38 [D:\a\1\s\Python\pylifecycle.c @ 2302]
04 000000dc`abfed580 00007fff`71aa8044 python39_d!_Py_FatalError_TstateNULL+0x10 [D:\a\1\s\Python\ceval.c @ 251]
05 000000dc`abfed5b0 00007fff`71aa6cf2 python39_d!_PyInterpreterState_GET+0x34 [D:\a\1\s\Include\internal\pycore_pystate.h @ 105]
06 000000dc`abfed5f0 00007fff`d0be13e7 python39_d!PyModule_Create2+0x12 [D:\a\1\s\Objects\moduleobject.c @ 168]
>>>> 07 000000dc`abfed620 00007fff`751165dc pymod!PyInit_pymod+0x27 [E:\projects\pymod\pymodmodule.cpp @ 19]
08 000000dc`abfed660 00007fff`751167ee python39!_PyImport_LoadDynamicModuleWithSpec+0x104 [C:\A\34\s\Python\importdl.c @ 165]
09 000000dc`abfed6d0 00007fff`75116749 python39!_imp_create_dynamic_impl+0x86 [C:\A\34\s\Python\import.c @ 2299]
0a 000000dc`abfed700 00007fff`750cb94b python39!_imp_create_dynamic+0x39 [C:\A\34\s\Python\clinic\import.c.h @ 330]
0b 000000dc`abfed730 00007fff`750ad500 python39!cfunction_vectorcall_FASTCALL+0x9b [C:\A\34\s\Objects\methodobject.c @ 426]
0c 000000dc`abfed7a0 00007fff`750ad2ef python39!PyVectorcall_Call+0x5c [C:\A\34\s\Objects\call.c @ 248]
0d 000000dc`abfed800 00007fff`750ad418 python39!_PyObject_Call+0x4f [C:\A\34\s\Objects\call.c @ 287]
0e (Inline Function) --------`-------- python39!PyObject_Call+0xc [C:\A\34\s\Objects\call.c @ 293]
0f 000000dc`abfed830 00007fff`7508c65f python39!do_call_core+0xb8 [C:\A\34\s\Python\ceval.c @ 5092]
10 000000dc`abfed880 00007fff`75083963 python39!_PyEval_EvalFrameDefault+0x5d6f [C:\A\34\s\Python\ceval.c @ 3581]
11 (Inline Function) --------`-------- python39!_PyEval_EvalFrame+0x13 [C:\A\34\s\Include\internal\pycore_ceval.h @ 40]
12 000000dc`abfedbb0 00007fff`750855a7 python39!_PyEval_EvalCode+0x2b3 [C:\A\34\s\Python\ceval.c @ 4327]
13 000000dc`abfedc80 00007fff`7508823d python39!_PyFunction_Vectorcall+0x257 [C:\A\34\s\Objects\call.c @ 396]
14 000000dc`abfedd80 00007fff`7508812f python39!_PyEval_EvalFrameDefault+0x194d [C:\A\34\s\Python\ceval.c @ 3487]
15 000000dc`abfee0b0 00007fff`750888e5 python39!_PyEval_EvalFrameDefault+0x183f [C:\A\34\s\Python\ceval.c @ 3504]
16 000000dc`abfee3e0 00007fff`750888e5 python39!_PyEval_EvalFrameDefault+0x1ff5 [C:\A\34\s\Python\ceval.c @ 3518]
17 000000dc`abfee710 00007fff`750888e5 python39!_PyEval_EvalFrameDefault+0x1ff5 [C:\A\34\s\Python\ceval.c @ 3518]
18 000000dc`abfeea40 00007fff`750854c4 python39!_PyEval_EvalFrameDefault+0x1ff5 [C:\A\34\s\Python\ceval.c @ 3518]
我找不到关于控制台消息的任何信息,也找不到 int3。我已尝试完全清除并重新安装/更新 Python。
谁能提供一些帮助或知道原因的方向?
编辑:修改 PyModule_pymod 函数以将 Pre 和 Post 消息显示到控制台。调试构建异常,Release 似乎不是:
PyMODINIT_FUNC PyInit_pymod(void)
printf("Pre-PyModule_Create\n");
PyObject *obj = PyModule_Create(&pymodmodule);
printf("Post-PyModule_Create\n");
return obj;
发布:
E:\projects\pymod\build\Release>python -c "import pymod"
Pre-PyModule_Create
Post-PyModule_Create
调试:
E:\projects\pymod\build\Debug>python -c "import pymod"
Pre-PyModule_Create
Fatal Python error: _PyInterpreterState_GET: the function must be called with the GIL held, but the GIL is released (the current Python thread state is NULL)
Python runtime state: unknown
【问题讨论】:
GIL 是“全局解释器锁”,显然,在调用任何 Python 基础设施之前,您必须持有它。 如果我调用 Py_Initialize(),GIL 锁定问题将停止,但这显然是针对嵌入在 C 代码中的 python。模块示例和教程不使用它。添加 Py_Initialize 时,我得到一个错误:SystemError:pymod 的初始化没有返回扩展模块。 PyModule_Create 执行时,我可以检查返回的 PyObject* 并查看 py_type 成员设置为“模块”。因此确信 Py_Initialize 不是解决方案。 遇到了同样的问题,但完全相同的代码(以及相同的 CmakeLists.txt)在 UNIX 上运行良好...没有 GIL 相关问题... 【参考方案1】:我遇到了和你一样的问题,在调试 TLS 结构时,我注意到 Visual Studio 加载了 python310.dll 而不是 python310_d.dll。
长话短说,当你定义_DEBUG宏时,Python.h会使用python310_d.lib,所以你需要运行调试版的Python:
python_d -c "import pymod"
我在使用 pybind11 时没有遇到这个问题,这让我更加困惑。事实证明,pybind11 在包含 Python.h 时取消了 _DEBUG 宏的定义,因此它始终使用 python310.lib 而不是 python310_d.lib,即使用于调试构建也是如此。
由于我没有在 Visual Studio 中看到使用 python_d 解释器的选项,我最终使用发布库使用以下代码调试构建:
#if defined(_MSC_VER) && defined(_DEBUG)
#undef _DEBUG
#include <Python.h>
#define _DEBUG 1
#else
#include <Python.h>
#endif
作为旁注,当您链接到 python310_d.dll 时,您必须将调试模块命名为 pymod_d.pyd 而不是 pymod.pyd。
【讨论】:
以上是关于Python3 C++ 模块 - 异常 - GIL 未持有的主要内容,如果未能解决你的问题,请参考以下文章