PyArray_Check使用CythonC ++给出分段错误

PyArray_Check使用CythonC ++给出分段错误,第1张

PyArray_Check使用Cython / C ++给出分段错误

快速修复 (有关详细信息和更复杂的方法,请继续阅读):

您需要

PyArray_API
通过调用
import_array()
以下命令在使用numpy-stuff的每个cpp文件中初始化变量:

//it is only a trick to ensure import_array() is called, when *.so is loaded//just called only onceint init_numpy(){     import_array(); // PyError if not successful     return 0;}const static int numpy_initialized =  init_numpy();void parse_ndarraray(PyObject *obj) { // would be called every time    if (PyArray_Check(obj)) {        cout << "PyArray_Check Passed" << endl;    } else {        cout << "PyArray_Check Failed" << endl;    }}

也可以使用

_import_array
,如果失败则返回负数,以使用自定义错误处理。有关的定义,请参见此处
import_array

警告: 正如@
isra60所指出的,

_import_array()/import_array()
只有在初始化Python之后(即在
Py_Initialize()
调用之后)才能调用。扩展总是如此,但如果嵌入了python解释器,则并非总是如此,因为它
numpy_initialized
是在
main
-starts之前初始化的。在这种情况下,不应使用“初始化技巧”,而应
init_numpy()
在之后调用
Py_Initialize()


精密的解决方案:

NB:有关信息,为什么

PyArray_API
需要设置,请参见以下SO-
answer:为了能够将符号解析推迟到运行时,因此在链接时不需要numpy的共享库,并且不能将其放在dynamic-library-路径(那么python的系统路径就足够了)。

提出的解决方案是快速的,但是如果使用numpy的cpp有多个,则其中一个会初始化很多PyArray_API实例。

如果

PyArray_API
不是将其定义为静态的,而是将其定义为
extern
一个翻译单元,则可以避免这种情况。对于那些翻译单元,
NO_import_ARRAY
必须先定义宏,然后
numpy/arrayobject.h
再包含宏。

但是,我们需要一个定义该符号的翻译单元。对于此翻译单元,

NO_import_ARRAY
不得定义宏。

但是,如果不定义宏,

PY_ARRAY_UNIQUE_SYMBOL
我们将仅获得一个静态符号,即对于其他翻译单元不可见,因此链接器将失败。这样做的原因是:如果有两个库,每个人都定义一个a,
PyArray_API
那么我们将对符号进行多重定义,并且链接器将失败,即,我们无法将这两个库一起使用。

因此,通过定义

PY_ARRAY_UNIQUE_SYMBOL
MY_FANCY_LIB_PyArray_API
每之前包括
numpy/arrayobject.h
我们有我们自己的
PyArray_API
-name,这不会与其他库发生冲突。

放在一起:

答: use_numpy.h-您包含numpy功能的标题,即

numpy/arrayobject.h

//use_numpy.h//your fancy name for the dedicated PyArray_API-symbol#define PY_ARRAY_UNIQUE_SYMBOL MY_PyArray_API//this macro must be defined for the translation unit   #ifndef INIT_NUMPY_ARRAY_CPP     #define NO_import_ARRAY //for usual translation units#endif//now, everything is setup, just include the numpy-arrays:#include <numpy/arrayobject.h>

B:

init_numpy_api.cpp
-用于初始化global的翻译单元
MY_PyArray_API

//init_numpy_api.cpp//first make clear, here we initialize the MY_PyArray_API#define INIT_NUMPY_ARRAY_CPP//now include the arrayobject.h, which defines//void **MyPyArray_API#inlcude "use_numpy.h"//now the old trick with initialization:int init_numpy(){     import_array();// PyError if not successful     return 0;}const static int numpy_initialized =  init_numpy();

C:

use_numpy.h
只要需要时就包含numpy,它将定义
extern void **MyPyArray_API

//example#include "use_numpy.h"...PyArray_Check(obj); // works, no segmentation error

警告: 不应忘记,

Py_Initialize()
必须已经调用了初始化技巧才能起作用。


为什么需要它 (出于历史原因保留):

当我用调试符号构建扩展名时:

extra_compile_args=['-fPIC', '-O0', '-g'],extra_link_args=['-O0', '-g'],

并使用gdb运行它:

 gdb --args python run_test.py (gdb) run  --- Segmentation fault (gdb) disass

我可以看到以下内容:

   0x00007ffff1d2a6d9 <+20>:    mov    0x203260(%rip),%rax   # 0x7ffff1f2d940 <_ZL11PyArray_API>   0x00007ffff1d2a6e0 <+27>:    add    
PyArray_Check
x10,%rax=> 0x00007ffff1d2a6e4 <+31>: mov (%rax),%rax ... (gdb) print $rax = 16

我们应该记住,这

#define PyArray_Check(op) PyObject_TypeCheck(op, &PyArray_Type)
仅是针对以下方面的定义:

&PyArray_Type

看来,这

PyArray_API
使用了某种方式
0
未初始化的一部分 (具有value
cpp_parser.cpp
)。

让我们看一下

-E
预处理器之后(与flag一起编译
 static void **PyArray_API= __null ... static int_import_array(void){  PyArray_API = (void **)PyCapsule_GetPointer(c_api,...

PyArray_AP

所以

_import_array(void)
我是静态的,并且通过初始化
_import_array()
,实际上可以解释我在构建期间收到的警告,该警告
PyArray_API
已定义但未使用-
我们未初始化
PyArray_API

因为

import_array()
是静态变量,所以必须在每个编译单元(即cpp-文件)中对其进行初始化。

因此,我们只需要这样做-似乎是官方方式。



欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zaji/5647977.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-12-16
下一篇2022-12-16

发表评论

登录后才能评论

评论列表(0条)

    保存