Я пытаюсь вызвать методы в классе Python из C ++. Метод C ++, из которого он вызывается, является обратным вызовом C ++.
В этом методе, когда я пытаюсь вызвать метод Python, он давал segmentation fault
,
Я сохранил экземпляр функции Python в глобальной переменной, такой как
// (pFunc is global variable of type PyObject*)
pFunc = PyDict_GetItemString(pDict, "PlxMsgWrapper");
где PlxMsgWrapper
это метод python, который будет использоваться в обратном вызове.
В обратном вызове аргументы создаются как
PyObject* args = PyTuple_Pack(2, PyString_FromString(header.c_str()),
PyString_FromString(payload.c_str()));
При создании
PyObject * pInstance = PyObject_CallObject(pFunc, args);
В этой строке дается ошибка сегментации. После этого фактический метод Python называется
PyObject* recv_msg_func = PyObject_GetAttrString(module, (char *)"recvCallback");
args = PyTuple_Pack(1, pInstance);
PyObject_CallObject(recv_msg_func, args);
Есть несколько вещей, которые вам нужно сделать, если вы вызываете функцию Python из обратного вызова C / C ++. Сначала, когда вы сохраняете свой объект функции Python, вам нужно увеличить счетчик ссылок с помощью:
Py_INCREF(pFunc)
В противном случае Python не знает, что вы держите ссылку на объект, и он может собрать мусор, что приведет к ошибке сегментации, когда вы попытаетесь использовать ее из своего обратного вызова.
Затем следующее, о чем вам нужно беспокоиться, это то, какой поток выполняется, когда вызывается ваш обратный вызов C / C ++. Если вам перезванивают из другого потока, не созданного на Python (то есть потока C / C ++, получающего данные в сокет), то вы ДОЛЖЕН получить глобальную блокировку интерпретатора Python (GIL) перед вызовом любых функций API Python. В противном случае поведение вашей программы не определено. Чтобы приобрести GIL, вы делаете:
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);
}
Кроме того, в функции init вашего модуля расширения вы должны сделать следующее, чтобы обеспечить правильную инициализацию потоков:
// 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();
}
В противном случае возможны сбои и странное поведение при попытке получить GIL из потока, не являющегося Python.
Увидеть Non-Python созданные темы для более подробной информации об этом.
Python должен искать модуль в каталоге, где он запускается
Однако, если вы считаете, что проблема в том, что Python не находит
ваш файл, вы можете добавить произвольный каталог на вашем компьютере к
Путь поиска модуля в вашей программе:
// 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();
}
Это не совсем отвечает на ваш вопрос, но вы можете значительно упростить свой код и избежать проблем со счетчиком ссылок Повысьте :: 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;
}