Python C API:WindowsError在创建了一些PyObject之后

Python C API:WindowsError在创建了一些PyObject之后,python,python-2.7,ctypes,python-c-api,Python,Python 2.7,Ctypes,Python C Api,让Python C API不给我错误一直是个问题 Background:我使用ctypes运行本机代码(C++)已经有一段时间了,但到目前为止,我还没有对Python C API做过任何具体的操作。我以前大部分都是从Python中传递结构,然后从C++中填充它们。我使用Struts的方式变得越来越麻烦,所以我决定尝试直接在C++中创建Python对象,然后把它们传递给我的Python脚本。 代码: 我有一个只有一个函数的DLL(Foo.DLL): #define N 223 __declspec

让Python C API不给我错误一直是个问题

Background:我使用
ctypes
运行本机代码(C++)已经有一段时间了,但到目前为止,我还没有对Python C API做过任何具体的操作。我以前大部分都是从Python中传递结构,然后从C++中填充它们。我使用Struts的方式变得越来越麻烦,所以我决定尝试直接在C++中创建Python对象,然后把它们传递给我的Python脚本。 代码: 我有一个只有一个函数的DLL(
Foo.DLL
):

#define N 223
__declspec(dllexport) void Bar(void)
{
    std::cout << "Bar" << std::endl;

    for (int i = 0; i < N; ++i)
    {
        auto list = PyList_New(0);
        std::cout << "Created: " << i << std::endl;
        //Py_DECREF(list);
    }
}
发生了什么:如果我在上面的DLL中将
N
定义为
222
或更低,代码工作正常(除了内存泄漏,但这不是问题所在)

如果我取消注释
//Py_DECREF(list)
行,代码工作正常

但是,通过上面的代码,我得到了以下结果:

Bar
Created: 0
Created: 1
Created: 2
...(omitted for your sake)
Created: 219
Created: 220
Created: 221
Traceback (most recent call last):
  File "C:\path_to_script\script.py", line 9, in <module>
    Foo.Bar()
WindowsError: exception: access violation reading 0x00000028
条
已创建:0
创建:1
创建:2
…(为了你的缘故省略)
创建:219
创建:220
创建:221
回溯(最近一次呼叫最后一次):
文件“C:\path\u to\u script\script.py”,第9行,在
Foo.Bar()
WindowsError:异常:访问冲突读取0x00000028
事实上,我在字典、列表、元组等方面也得到了同样的结果。如果我创建一个列表,然后将空的子列表附加到该列表,则会得到相同的结果

更奇怪的是,我在实际Python脚本中创建的每个列表都会减少DLL在出现此windows错误之前可以创建的列表数量

更奇怪的是,如果我在python脚本中创建了超过222个列表,那么DLL在创建了大约720个列表之前不会遇到这个错误

**其他详情:**

  • 视窗10
  • 使用Anaconda2 32位Python 2.7发行版
  • (使用该发行版中的
    Python.h
    python27.lib
  • python.exe--版本:
    2.7.13::Anaconda自定义(32位)
  • 使用Visual Studio 2017创建DLL
<> P>只要我不从C++代码中创建许多<代码> pyObjult/Cuth>s,一切都看起来很好。我可以通过Python代码传递<代码> pyObjs<代码> s,而且它工作得很好。直到我在C++代码中创建了“太多”对象。

发生了什么事?

Python全局解释器锁在调用这些库导出的任何函数之前释放,然后重新获取

这使得使用Python C API代码变得不安全。正如您所发现的,它失败的确切原因是不可预测的。我想这与分配是否触发垃圾收集器运行有关,但我认为不值得花费太多时间来找出确切的原因

有(至少)两种解决方案可供选择:

  • 使用
    ctypes.PyDLL
    (文档注释与
    CDLL
    类似,只是它不释放GIL)
  • >P>在C++代码中重新获取吉尔-一个简单的方法是:

    auto state = PyGILState_Ensure();
    // C++ code requiring GIL - probably your entire loop
    PyGILState_Release(state);
    
    :

    Python全局解释器锁在调用这些库导出的任何函数之前释放,然后重新获取

    这使得使用Python C API代码变得不安全。正如您所发现的,它失败的确切原因是不可预测的。我想这与分配是否触发垃圾收集器运行有关,但我认为不值得花费太多时间来找出确切的原因

    有(至少)两种解决方案可供选择:

  • 使用
    ctypes.PyDLL
    (文档注释与
    CDLL
    类似,只是它不释放GIL)
  • >P>在C++代码中重新获取吉尔-一个简单的方法是:

    auto state = PyGILState_Ensure();
    // C++ code requiring GIL - probably your entire loop
    PyGILState_Release(state);
    

    我已经证实,这两种解决方案似乎都能解决问题。他们怎么敢期望我真正阅读文档呢?谢谢。值得一提的是,我从“使用Python C API执行简单操作时出现的神秘错误通常是由于GIL或未初始化Python”的想法开始工作然后只是在ctypes文档中搜索GIL。我也没有仔细阅读文档。我已经确认这两种解决方案似乎都能解决问题。他们怎么敢期望我真正阅读文档呢?谢谢。值得一提的是,我从以下想法开始工作:“当你使用Python C API做一些简单的事情时,神秘的错误通常是由于GIL或没有初始化Python造成的”,然后只是在ctypes文档中搜索GIL。我实际上也没有详细阅读文档。