从C调用蟒蛇法++(或C)回调 [英] Calling python method from C++ (or C) callback

查看:249
本文介绍了从C调用蟒蛇法++(或C)回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图调用从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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆