2012-07-11 28 views
8

Tôi có một tiện ích wx.py.Shell.shell cho phép người dùng thực thi mã python tương tác với chương trình của tôi. Tôi muốn để có thể vượt qua một chức năng mà người dùng xác định trong không gian này để mã C++ của tôi (Thông qua các wrapper wxswig tạo ra xung quanh widget tùy chỉnh của tôi) và thực hiện nó.Gọi lại Python từ SWIG PyObject_Call Segfault

Trong C++ của tôi mã tôi đang sử dụng một std :: chức năng <> lớp để gọi chức năng ràng buộc (C++ hay Python)

Vì vậy, tôi đã tạo ra một lớp đơn giản để quấn PyObject với các nhà điều hành chức năng cuộc gọi. Tuy nhiên tôi nhận được một segfault khi tôi cố gắng gọi 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); 
} 

Trong nỗ lực của tôi để tìm hiểu những gì đang xảy ra, tôi đặt một loạt các câu lệnh in. Một trong số đó in tên loại và tham chiếu đếm dòng trước khi segfault. Điều này dẫn đến "hàm 3" vì vậy tôi phải thừa nhận hàm chưa bị hủy.

Tôi đang đi qua những điều sau đây để uống một lân:

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

Trong đó tôi xây dựng một PyMenuCallback

Tôi đang ở một mất mát cho những gì đang gây ra segfault, bất kỳ ý tưởng?

+1

tôi nghĩ rằng bạn đã vi phạm [cai trị của ba] (http://stackoverflow.com/questions/4172722/what-is-the-rule-of-ba) bằng cách không cung cấp 'toán tử =' cho 'PyMenuCallback'. Tôi không chắc đó có phải là vấn đề ở đây hay không, nhưng nó chắc chắn có khả năng gây ra vấn đề. – Flexo

+0

Tôi không thể tạo lại điều này trên máy của mình bằng một trường hợp thử nghiệm. Tôi quản lý để xác nhận rằng 'operator =' không được sử dụng một cách tình cờ, nhưng mã đã làm việc và không tạo ra bất kỳ cảnh báo nào từ valgrind. Bạn có thể mở rộng và đơn giản hóa trường hợp thử nghiệm của bạn một chút có lẽ bằng cách sử dụng '% inline' và'% {%} 'để làm cho nó để bạn chỉ có một tệp giao diện duy nhất? Ví dụ. Tôi đã sử dụng: [this] (http://pastebin.com/XYXj3a4p) để kiểm tra mà có thể có sự khác biệt tinh tế với những gì bạn đang sử dụng/gói. – Flexo

+1

Thật vậy, bắt tốt, tôi quên toán tử =. Tuy nhiên nó không được sử dụng vào lúc này, nhưng tôi sẽ thêm nó. – Tocs

Trả lời

3

Kể từ khi C++ gọi callback python là trong vòng một wxWidget, và wrapper uống một lân được tạo ra bởi đặc biệt wxPython uống một lân (wxswig?) Có một số bảo vệ chủ đề cần thiết xung quanh gọi hàm ...

Các cố định nhà điều hành nên xem xét như thế này

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); 
} 

Hãy chắc chắn bao gồm

#include "wx/wxPython/wxPython.h" 
#include "wx/wxPython/wxPython_int.h" 
Các vấn đề liên quan