尝试从C调用Python函数时出现Segfault

尝试从C调用Python函数时出现Segfault,python,c,function,callback,call,Python,C,Function,Callback,Call,所以,我想从C调用一个Python回调函数 在某个时刻,函数被发送到C并打包成如下的元组 PyObject *userData = Py_BuildValue("Oi",py_callback,some_number); 在那个区域的某个地方,我也做了Py\u INCREF(Py\u callback)。 在程序稍后的某个时候,我想调用该函数 PyObject *py_callback; int some_number; PyArg_ParseTuple((PyObject*)userData

所以,我想从C调用一个Python回调函数

在某个时刻,函数被发送到C并打包成如下的元组

PyObject *userData = Py_BuildValue("Oi",py_callback,some_number);
在那个区域的某个地方,我也做了
Py\u INCREF(Py\u callback)

在程序稍后的某个时候,我想调用该函数

PyObject *py_callback;
int some_number;
PyArg_ParseTuple((PyObject*)userData,"Oi",&py_callback,&some_number); // returns true
PyObject *py_result = PyObject_CallFunctionObjArgs(py_callback,
                                                   /* ... */
                                                   NULL);

最后一个调用抛出了一个分段错误。你知道它为什么会这样做吗?

当从Python C API获得奇怪的行为时,总是需要仔细检查是否正确管理全局解释器锁(也称为“GIL”)的状态:

当从Python C API获得奇怪的行为时,您是否正确管理全局解释器锁(也称为“GIL”)的状态始终值得仔细检查:

我不知道为什么这里每个人都在谈论GIL。你在哪里发布它?我注意到下面列出的几个可能的故障点。它夹杂着各种建议

我注意到您没有增加
userData
的引用计数。为什么不呢?你在储存它,是吗?为什么要将其存储在元组中?为什么不保留两个变量(用于回调和数据),然后增加它们的refcounts,这样您就拥有了一个引用

首先,检查所有函数的返回值,看看它们是否
NULL
。这将让你确保你实际上运行正常。使用
PyObject\u Print
在代码中的所有点打印您感兴趣的对象,以确保事情按预期进行,这可能也是一个好主意

从您对segfault发生位置的评论中,我猜您在使用
PyObject\u CallFunctionObjArgs
调用回调函数时,向回调函数传递了错误数量的参数。你能再检查一下吗?可能会向我们显示回调函数定义,然后再次检查调用


我看到的另一个可能的问题是,从命名来看,
py\u some\u number
听起来像是一个Python整数对象。事实并非如此。在
PyArg\u语法元组之后,它将包含一个整数

我不知道为什么大家都在谈论吉尔。你在哪里发布它?我注意到下面列出的几个可能的故障点。它夹杂着各种建议

我注意到您没有增加
userData
的引用计数。为什么不呢?你在储存它,是吗?为什么要将其存储在元组中?为什么不保留两个变量(用于回调和数据),然后增加它们的refcounts,这样您就拥有了一个引用

首先,检查所有函数的返回值,看看它们是否
NULL
。这将让你确保你实际上运行正常。使用
PyObject\u Print
在代码中的所有点打印您感兴趣的对象,以确保事情按预期进行,这可能也是一个好主意

从您对segfault发生位置的评论中,我猜您在使用
PyObject\u CallFunctionObjArgs
调用回调函数时,向回调函数传递了错误数量的参数。你能再检查一下吗?可能会向我们显示回调函数定义,然后再次检查调用


我看到的另一个可能的问题是,从命名来看,
py\u some\u number
听起来像是一个Python整数对象。事实并非如此。在
PyArg\u语法元组之后,它将包含一个整数

在调试模式下编译,在GDB中加载,并获得回溯跟踪。您是否确保在调用Python之前保留GIL?我发现了另一个更可能的问题(请参阅我的答案)。如果这仍然不起作用,我们应该为您提供足够的谷歌素材,以寻找一些更容易理解的解释,说明如何处理CPython解释器锁。@ncoghlan:您的建议是正确的:这个问题可以通过GIL states解决。如果您将您的评论表述为一个问题,我将接受它。在调试模式下编译,在GDB中加载,并获得回溯。您是否确保在调用Python之前保留GIL?我发现了一个不同的问题,它更可能是罪魁祸首(见我的答案)。如果这仍然不起作用,我们应该为您提供足够的谷歌素材,以寻找一些更容易理解的解释,说明如何处理CPython解释器锁。@ncoghlan:您的建议是正确的:这个问题可以通过GIL states解决。如果你把你的评论表述成一个问题,我会接受的。哦,对不起。那是个打字错误。我相应地更正了问题。这仍然没有意义-您将什么作为第二个参数传递给
PyObject\u callfunctionrgs
<代码>&某些\u编号
无法正常工作(类型错误),并且您在当前版本中根本没有初始化
py\u某些\u编号
。既然您想回调用Python,那么使用
“OO”
并将数字保留为
PyObject
就是您想要做的。当然,您是对的。事实上,我发现无论如何我都不需要这个数字。我用GIL管理文档的引用替换了我的原始答案,因为那个评论最终解决了真正的问题,而元组解析问题只影响了SO问题,而不是真正的代码。哦,我很抱歉。那是个打字错误。我相应地更正了问题。这仍然没有意义-您将什么作为第二个参数传递给
PyObject\u callfunctionrgs
<代码>&某些\u编号
无法正常工作(类型错误),并且您在当前版本中根本没有初始化
py\u某些\u编号
。既然您想回调用Python,那么使用
“OO”
并将数字保留为
PyObject
就是您想要做的。当然,您是对的。事实上我发现我根本不需要那个号码