从C调用蟒蛇法++(或C)回调 [英] Calling python method from C++ (or C) callback
问题描述
我试图调用从C ++ Python类的方法。 C ++的方法,从这个被称为是一个C ++回调。
在这个方法中,当我试图调用Python方法,它是给分段故障
。
我在一个全局变量保存Python函数的一个实例像
//(pFunc的类型的PyObject的全局变量*)
pFunc = PyDict_GetItemString(pDictPlxMsgWrapper);
其中, PlxMsgWrapper
是一个Python方法,它会在回调中使用。
在回调,参数创建为
的PyObject * ARGS = PyTuple_Pack(2 PyString_FromString(header.c_str()),
PyString_FromString(payload.c_str()));
创建当
的PyObject * pInstance = PyObject_CallObject(pFunc,参数);
在该行给予其分段故障。在此之后,实际的Python方法称为
的PyObject * recv_msg_func = PyObject_GetAttrString(模块(字符*)recvCallback);
ARGS = PyTuple_Pack(1,pInstance);
PyObject_CallObject(recv_msg_func,参数);
有你需要做的,如果你是从C / C ++回调调用Python函数的几件事情。首先,当你保存了你的Python函数对象,你需要用递增引用计数:
Py_INCREF(pFunc)
否则Python有不知道你持有到一个对象的引用,它可以收集垃圾的,造成了分段错误,当您尝试从回调中使用它。
这时旁边,你需要关心的事情是被调用的C / C ++的回调时,线程运行的产品。如果您收到来自其他非Python中叫回创建的线程(即C / C ++线程套接字接收数据),那么您必须获得Python的全球国米preTER锁(GIL)前调用任何的Python API函数。否则,你的程序的行为是不确定的。为了获取GIL你做的:
的回调(){
PyGILState_STATE gstate;
gstate = PyGILState_Ensure(); //获取ARGS等。 //调用你的Python函数对象
*的PyObject = pInstance PyObject_CallObject(pFunc,参数); //是否有任何其他的Python所需的API操作 //释放线程。没有的Python API允许超出了这一点。
PyGILState_Release(gstate);
}
另外,在扩展模块的初始化函数,你应该做到以下几点,以确保线程正确初始化:
//确保GIL已经创建,因为我们需要获得它在我们的
//回调,安全地调用到Python应用程序。
如果(!PyEval_ThreadsInitialized()){
PyEval_InitThreads();
}
另外,当您试图从非Python的线程获得GIL崩溃和奇怪的行为可能会随之而来。
请参阅Non-Python创建的线程的详细的这一点。
I am trying to call methods in a python class from C++. The C++ method from which this is called is a C++ callback.
Within this method when I am trying to call python method, it was giving segmentation fault
.
I have saved an instance of python function in a global variable like
// (pFunc is global variable of type PyObject*)
pFunc = PyDict_GetItemString(pDict, "PlxMsgWrapper");
where PlxMsgWrapper
is a python method, which will be used in the callback.
In the callback, the arguments are created as
PyObject* args = PyTuple_Pack(2, PyString_FromString(header.c_str()),
PyString_FromString(payload.c_str()));
When creating the
PyObject * pInstance = PyObject_CallObject(pFunc, args);
In this line its giving segmentation fault. After this the actual python method is called as
PyObject* recv_msg_func = PyObject_GetAttrString(module, (char *)"recvCallback");
args = PyTuple_Pack(1, pInstance);
PyObject_CallObject(recv_msg_func, args);
There are a few things you need to do if you are invoking a Python function from a C/C++ callback. First when you save off your python function object, you need to increment the reference count with:
Py_INCREF(pFunc)
Otherwise Python has no idea you are holding onto an object reference, and it may garbage collect it, resulting in a segmentation fault when you try to use it from your callback.
Then next thing you need to be concerned about is what thread is running when your C/C++ callback is invoked. If you are getting called back from another non-Python created thread (i.e. a C/C++ thread receiving data on a socket), then you MUST acquire Python's Global Interpreter Lock (GIL) before calling any Python API functions. Otherwise your program's behavior is undefined. To acquire the GIL you do:
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);
}
Also, in your extension module's init function, you should do the following to ensure that threading is properly initialized:
// 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();
}
Otherwise, crashes and strange behavior may ensue when you attempt to acquire the GIL from a non-Python thread.
See Non-Python Created Threads for more detail on this.
这篇关于从C调用蟒蛇法++(或C)回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!