Python回调从SWIG PyObject_Call Segfault [英] Python Callback from SWIG PyObject_Call Segfault

查看:939
本文介绍了Python回调从SWIG PyObject_Call Segfault的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个wx.py.Shell.shell小部件,让用户执行与我的程序交互的python代码。我想能够传递一个函数,用户在这个空间中定义到我的C ++代码(通过wxswig生成包装我的自定义窗口小部件)并执行它。



在我的C ++代码中,我使用一个std :: function<类来调用绑定的函数(C ++或Python)



所以我创建了一个简单的类PyObject带有函数调用操作符。但是当我尝试调用PyObject *时,我得到一个segfault。

  class PyMenuCallback 
{
PyObject * Func;
public:
PyMenuCallback(const PyMenuCallback& op2);
PyMenuCallback(PyObject * func);
〜PyMenuCallback();

void operator()(int id);
};
//////////////////////////////////////////////// ///////////
PyMenuCallback :: PyMenuCallback(PyObject * func)
:Func(func)
{
Py_XINCREF(Func);
if(!PyCallable_Check(Func))
cout<< 不是可回调的回调。 << endl //抛出异常或某事
}

PyMenuCallback :: PyMenuCallback(const PyMenuCallback& op2)
:Func(op2.Func)
{
Py_XINCREF(Func);
if(!PyCallable_Check(Func))
cout<< 不是可回调的回调。 << endl
}

PyMenuCallback ::〜PyMenuCallback()
{
Py_XDECREF(Func);
}

void PyMenuCallback :: operator()(int id)
{
cout< Calling Callback< endl
if(Func == 0 || Func == Py_None ||!PyCallable_Check(Func))
return;
cout<< 构建Arg< endl
PyObject * arglist = Py_BuildValue((i),id);
cout<< Func:<< Func-> ob_type-> tp_name<< < Func-> ob_refcnt<< endl
PyObject * result = PyObject_Call(Func,arglist,0); //<<< --- SEGFAULTS HERE
cout<< 执行<< endl
Py_DECREF(arglist);
Py_XDECREF(result);
}



在我试图找到发生了什么,我把一堆打印语句。
其中之一打印segfault之前的行的类型名称和引用计数。这会导致函数3,所以我必须假设该函数还没有被销毁。



我将以下内容传递给swig:

  void AddOption(std :: string name,PyObject * pycallback); 

其中我构造了一个PyMenuCallback



解决方案

由于C ++调用python回调函数是在一个wxWidget,swig包装器是由特殊的wxPython swig(wxswig?)生成的。函数调用需要一些线程保护...



像这样

  void PyMenuCallback :: operator()(int id)
{
cout< ; Calling Callback< endl
if(Func == 0 || Func == Py_None ||!PyCallable_Check(Func))
return;
cout<< 构建Arg< endl
PyObject * arglist = Py_BuildValue((i),id);
cout<< Built:<< arglist<< endl
cout<< Func:<< Func-> ob_type-> tp_name<< < Func-> ob_refcnt<< endl

wxPyBlock_t blocked = wxPyBeginBlockThreads(); // Anti-WxSwig

PyObject * result = PyObject_Call(Func,arglist,0);

wxPyEndBlockThreads(blocked);


cout<< Executed<< endl
Py_XDECREF(arglist);
Py_XDECREF(result);
}

请务必包括

  #includewx / wxPython / wxPython.h
#includewx / wxPython / wxPython_int.h
/ pre>

I have a wx.py.Shell.shell widget which lets the user execute python code that interacts with my program. I want to be able to pass a function that the user defines in this space to my C++ code (Through the wxswig generated wrapper around my custom widget)and execute it.

In my C++ code I'm using a std::function <> class to invoke bound functions (C++ or Python)

So I created a simple class to wrap the PyObject with the function call operator. However I get a segfault when I try to call the PyObject *.

class PyMenuCallback
{
    PyObject *Func;
public:
    PyMenuCallback(const PyMenuCallback &op2);
    PyMenuCallback(PyObject *func);
    ~PyMenuCallback ();

    void operator() (int id);
};
/////////////////////////////////////////////////////////
PyMenuCallback::PyMenuCallback(PyObject *func)
    : Func(func)
{
    Py_XINCREF (Func);
    if(!PyCallable_Check(Func))
        cout << "Not a Callable Callback." << endl; //Throw an exception or something
}

PyMenuCallback::PyMenuCallback(const PyMenuCallback &op2)
    : Func (op2.Func)
{
    Py_XINCREF (Func);
    if(!PyCallable_Check(Func))
        cout << "Not a Callable Callback." << endl;
}

PyMenuCallback::~PyMenuCallback()
{
    Py_XDECREF (Func);
}

void PyMenuCallback::operator() (int id)
{
    cout << "Calling Callback" << endl;
    if (Func == 0 || Func == Py_None || !PyCallable_Check(Func))
        return;
    cout << "Building Args" << endl;   
    PyObject *arglist = Py_BuildValue ("(i)",id);
    cout << "Func: " << Func->ob_type->tp_name << " " << Func->ob_refcnt << endl;
    PyObject *result = PyObject_Call(Func,arglist,0); //<<<<<---SEGFAULTS HERE
    cout << "Executed" << endl;
    Py_DECREF(arglist);
    Py_XDECREF(result);
}

In my attempts to find what was going on, I put a bunch of print statements. One of which prints the type name and reference count the line before the segfault. This results in "function 3" so I have to assume the function has not been destroyed yet.

I'm passing the following to swig:

void AddOption (std::string name, PyObject *pycallback);

In which I construct a PyMenuCallback

I'm at a loss for what's causing the segfault, any ideas?

解决方案

Since the C++ calling the python callback is within a wxWidget, and the swig wrapper is generated by the special wxPython swig (wxswig?) There is some thread protection required around the function call...

The fixed operator should look like this

void PyMenuCallback::operator() (int id)
{
    cout << "Calling Callback" << endl;
    if (Func == 0 || Func == Py_None || !PyCallable_Check(Func))
        return;
    cout << "Building Args" << endl;   
    PyObject *arglist = Py_BuildValue ("(i)",id);
    cout << "Built: " << arglist << endl;
    cout << "Func: " << Func->ob_type->tp_name << " " << Func->ob_refcnt << endl;

    wxPyBlock_t blocked = wxPyBeginBlockThreads(); //Anti-WxSwig 

    PyObject *result = PyObject_Call(Func,arglist,0);

    wxPyEndBlockThreads(blocked);


    cout << "Executed" << endl;
    Py_XDECREF(arglist);
    Py_XDECREF(result);
}

Make sure to include

#include "wx/wxPython/wxPython.h"
#include "wx/wxPython/wxPython_int.h"

这篇关于Python回调从SWIG PyObject_Call Segfault的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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