2013-05-17 1 views
13

C++에서 파이썬 클래스의 메서드를 호출하려고합니다. 이것이 호출되는 C++ 메소드는 C++ 콜백입니다.C++ (또는 C) 콜백에서 파이썬 메서드 호출

파이썬 메서드를 호출 할 때이 메서드 내에서 segmentation fault을 제공하고있었습니다.

PlxMsgWrapper 콜백에 사용될 파이썬 방법이다

// (pFunc is global variable of type PyObject*) 
pFunc = PyDict_GetItemString(pDict, "PlxMsgWrapper"); 

같은 전역 변수 파이썬 함수의 인스턴스를 저장했다. 그 세분화 결함이주는 라인에

PyObject * pInstance = PyObject_CallObject(pFunc, args); 

를 만들 때 콜백

는 인수

PyObject* args = PyTuple_Pack(2, PyString_FromString(header.c_str()), 
           PyString_FromString(payload.c_str())); 

으로 생성된다. 이 후 실제 파이썬 방법은

라고한다
PyObject* recv_msg_func = PyObject_GetAttrString(module, (char *)"recvCallback"); 
args = PyTuple_Pack(1, pInstance); 
PyObject_CallObject(recv_msg_func, args); 
+0

나는 올바르게 설명하기 위해 최선을 다했습니다.문제가 있으면 다시 의견을 말하십시오. – Chaitanya

+0

PyObject_GetAttrString이 실제로 사용할 수있는 것을 반환하는지 확인 했습니까? 어쩌면 조회가 어떤 이유로 실패했습니다. 아마도 '모듈'이 올바르게 초기화되지 않았습니까? – djf

+0

@djf 사실, 컨트롤 자체는 그 시점까지 오지 않습니다. 'PyObject_CallObject (pFunc, args)'를 참조하십시오. 이 메서드 자체를 호출하는 동안 충돌이 발생합니다. 모듈 문제를 없애기 위해 콜백에로드하지 않습니다. – Chaitanya

답변

27

. 당신이 당신의 파이썬 함수 객체를 저장할 때 첫째, 당신의 참조 카운트를 증가해야합니다

Py_INCREF(pFunc) 

그렇지 않으면 파이썬은 객체 참조에 들고 아무 생각이 없다, 그것은 쓰레기는 분할의 결과를 수집 할 수 있습니다 콜백에서 사용하려고하면 오류가 발생합니다.

그런 다음 걱정해야 할 것은 C/C++ 콜백이 호출 될 때 실행중인 스레드입니다. 파이썬이 아닌 다른 스레드 (즉, 소켓의 데이터를받는 C/C++ 스레드)에서 콜백을 받았다면 은 파이썬 API 함수를 호출하기 전에 파이썬의 GIL (Global Interpreter Lock)을 획득해야합니다. 그렇지 않으면 프로그램의 동작이 정의되지 않습니다.

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

그렇지 않으면, 충돌 및 비정상적인 동작이 수

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

또한, 확장 모듈의 초기화 함수에서, 당신은 제대로 초기화되는 스레딩을 보장하기 위해 다음을 수행해야 다음 GIL을 획득하려면 당신이 비 파이썬 스레드에서 GIL을 얻으려고 시도 할 때 발생합니다.

자세한 내용은 Non-Python Created Threads을 참조하십시오.

+1

고마워요. :) 그것은 정확한 문제였습니다. – Chaitanya

+0

고마워요. 내가 틀린 실로 있다고 생각하지 않았습니다. – eddiewould

2

당신은 문제가 파이썬 파일을 발견되지 않는다는이라고 생각하면 파이썬은, 그것은 그러나,에서 실행 되고있는 디렉토리에 모듈을 찾아야한다 , 당신은 당신의 프로그램 내에서 모듈 검색 경로에 컴퓨터에 임의의 디렉토리를 추가 할 수 있습니다 : 당신은 C/C++ 콜백에서 파이썬 함수를 호출하는 경우 당신이해야 할 몇 가지가 있습니다

// 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(); 
} 
2

이 질문에 대한 답변은 정확하지 않지만 코드를 크게 단순화하고 참조 번호 문제는 Boost::Python으로 피할 수 있습니다.

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