C++ 从C++;(C)收回
我试图调用C++中的Python类中的方法。从中调用的C++方法是C++回调。< /P> 在这个方法中,当我试图调用python方法时,它给出了C++ 从C++;(C)收回,c++,python,c,callback,python-c-api,C++,Python,C,Callback,Python C Api,我试图调用C++中的Python类中的方法。从中调用的C++方法是C++回调。< /P> 在这个方法中,当我试图调用python方法时,它给出了分段错误 我已经将python函数的一个实例保存在一个全局变量中,如 // (pFunc is global variable of type PyObject*) pFunc = PyDict_GetItemString(pDict, "PlxMsgWrapper"); 其中PlxMsgWrapper是一个python方法,将在回调中使用 在回调中,
分段错误
我已经将python函数的一个实例保存在一个全局变量中,如
// (pFunc is global variable of type PyObject*)
pFunc = PyDict_GetItemString(pDict, "PlxMsgWrapper");
其中PlxMsgWrapper
是一个python方法,将在回调中使用
在回调中,参数被创建为
PyObject* args = PyTuple_Pack(2, PyString_FromString(header.c_str()),
PyString_FromString(payload.c_str()));
在创建
PyObject * pInstance = PyObject_CallObject(pFunc, args);
在这一行中,它给出了分段错误。在此之后,实际的python方法被称为
PyObject* recv_msg_func = PyObject_GetAttrString(module, (char *)"recvCallback");
args = PyTuple_Pack(1, pInstance);
PyObject_CallObject(recv_msg_func, args);
Python应该在运行它的目录中查找模块 但是,如果您认为问题在于python没有找到 您可以将计算机上的任意目录添加到 程序中的模块搜索路径:
// Initialize the Python Interpreter
Py_Initialize();
// The following two lines to the trick:
// add path to your module to python's search paths
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append(\"/path/to/python/module/here\")");
// Build the name object
pName = PyString_FromString("your_module");
// Load the module object
pModule = PyImport_Import(pName);
// pDict is a borrowed reference
pDict = PyModule_GetDict(pModule);
// pFunc is also a borrowed reference
pFunc = PyDict_GetItemString(pDict, "PlxMsgWrapper");
pArgs = ...
if (PyCallable_Check(pFunc))
{
PyObject_CallObject(pFunc, pArgs);
} else {
PyErr_Print();
}
如果要从C/C++回调调用Python函数,需要做一些事情。首先,在保存python函数对象时,需要使用以下命令增加引用计数:
Py_INCREF(pFunc)
否则,Python不知道您正在保留一个对象引用,它可能会对它进行垃圾收集,从而在您试图从回调中使用它时导致分段错误
然后,您需要关心的下一件事是调用C/C++回调时运行的线程。如果您从另一个非Python创建的线程(即在套接字上接收数据的C/C++线程)被回调,那么您必须在调用任何Python API函数之前获得Python的全局解释器锁(GIL)。否则,程序的行为是未定义的。要获得GIL,您需要:
void callback() {
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
// Get args, etc.
// Call your Python function object
PyObject * pInstance = PyObject_CallObject(pFunc, args);
// Do any other needed Python API operations
// Release the thread. No Python API allowed beyond this point.
PyGILState_Release(gstate);
}
此外,在扩展模块的init函数中,应执行以下操作以确保线程正确初始化:
// Make sure the GIL has been created since we need to acquire it in our
// callback to safely call into the python application.
if (! PyEval_ThreadsInitialized()) {
PyEval_InitThreads();
}
否则,当您试图从非Python线程获取GIL时,可能会发生崩溃和奇怪的行为
有关这方面的更多详细信息,请参阅。这并不能准确回答您的问题,但您可以大大简化代码,避免引用计数问题
我已经尽了最大的努力来恰当地阐明。如果有任何问题,请回复。是否检查PyObject_GetAttrString是否实际返回可用的内容?可能由于某种原因,查找失败。也许“模块”没有正确初始化?@djf实际上,控件本身直到那时才出现
PyObject\u CallObject(pFunc,args)
。它在调用此方法本身时崩溃。为了摆脱模块问题,我没有在回调中加载它。啊,我明白了。我误解了这个问题。您是否可以展示一个完整的代码示例?如果PyObject_CallObject segfaults,很可能是因为pFunc或args没有正确初始化。@djfargs
在回调本身中正确初始化。这不是问题<代码>pFunc
在全球范围内存在。我怀疑并正在回调
本身中初始化pFunc
。但问题还是来了。非常感谢。:)这正是问题所在。非常感谢——我没有考虑到我可能会走错方向。
#include "boost/python.hpp"
using namespace boost::python;
int main()
{
Py_Initialize();
object pyFunPlxMsgWrapper = import("your_module").attr("PlxMsgWrapper");
pyFunPlxMsgWrapper(2, "string", "data");
return 0;
}