Segfault при попытке вызвать функцию Python из C

1

Итак, я хочу вызвать функцию обратного вызова Python из C.

В какой-то момент функция отправляется на C и упаковывается в кортеж, подобный этому

PyObject *userData = Py_BuildValue("Oi",py_callback,some_number);

Где-то в этой области я тоже Py_INCREF(py_callback).
В какой-то более поздний момент в программе я хочу вызвать эту функцию

PyObject *py_callback;
int some_number;
PyArg_ParseTuple((PyObject*)userData,"Oi",&py_callback,&some_number); // returns true
PyObject *py_result = PyObject_CallFunctionObjArgs(py_callback,
                                                   /* ... */
                                                   NULL);

и последний вызов вызывает ошибку сегментации. Есть ли у вас какие-либо идеи, почему бы это сделать?

  • 1
    Скомпилируйте в режиме отладки, загрузите его в GDB и получите обратную трассировку.
  • 1
    Вы уверены, что держите GIL перед тем, как перезвонить в Python?
Показать ещё 2 комментария
Теги:
callback
call
function

2 ответа

5
Лучший ответ

Когда вы получаете странное поведение из API Python C, всегда стоит дважды проверить, что вы правильно управляете состоянием Global Interpreter Lock (aka "GIL" ): http://docs.python.org/c-api/init.html#thread-state-and-the-global-interpreter-lock

  • 0
    Ой, простите. Это была опечатка. Я исправил вопрос соответственно.
  • 0
    Это все еще не имеет смысла - что вы передаете в качестве второго аргумента PyObject_CallFunctionArgs ? &some_number не будет работать правильно (это неправильный тип), и вы не инициализируете py_some_number вообще в текущей версии. Поскольку вы хотите перезвонить в Python, используйте "OO" и сохраните номер в качестве PyObject .
Показать ещё 2 комментария
1

Я не уверен, почему все говорят о GIL здесь. Вы выпускаете его где угодно? Я замечаю несколько возможных проблем, которые я приведу ниже. Он смешался с предложениями.

Я заметил, что вы не увеличиваете количество ссылок userData. Почему нет? Вы храните его, не так ли? Почему вы хотите сохранить его в кортеже? Почему бы просто не сохранить две переменные (для обратного вызова и данные), а затем увеличить их количество, чтобы вы имели ссылку?

Прежде всего, проверьте возвращаемые значения всех ваших функций, чтобы увидеть, являются ли они NULL. Это позволит вам убедиться, что вы действительно работаете должным образом. Также неплохо использовать PyObject_Print для печати объектов, которые вас интересуют, во всех точках кода, чтобы убедиться, что все идет так, как вы ожидаете.

Из вашего комментария о том, где происходит segfault, я предполагаю, что вы передаете неправильное количество параметров своей функции обратного вызова, когда вы вызываете ее с помощью PyObject_CallFunctionObjArgs. Вы можете проверить его дважды? Возможно, покажите нам свое определение функции обратного вызова, а затем снова проверьте вызов.

Другая возможная проблема, которую я вижу, заключается в том, что из имен, py_some_number звучит так, как вы ожидаете целочисленный объект Python. Это не тот случай. После PyArg_ParseTuple он будет содержать целое число.

  • 0
    Функция обратного вызова C должна соответствовать определению функции Portaudio, поэтому userData может быть только одним указателем. Я проверил и дважды проверил все вызовы и аргументы, и они определенно верны. Спасибо за подсказку об увеличении refcounts, хотя!
  • 1
    Мне тогда любопытно. Какие изменения исправили проблему?
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню