Segfault в многопоточном расширении Python на C - PullRequest
4 голосов
/ 19 марта 2010

У меня есть очень урезанный пример, который создает segfault, от которого я не могу избавиться. Скрипт Python вызывает функцию C в расширении, которое создает новый поток, используя pthreads. Я использую PyGILState_Ensure и PyGILState_Release вокруг моего вызова Python (PyRun_SimpleString) в новом потоке, но, возможно, я их не правильно использую или пропустил какой-то другой шаг. Закомментируя вызовы python в функции receive_audio, segfault больше не происходит. Есть идеи?

Выход:

python lib / test.py
(Основная тема) initmodule завершен
(Основная тема) Вызов run_thread ()
(Основная тема) Создание темы
(Новая тема) В receive_audio () - получение GIL
(Новая тема) python print!
(Новая тема) В receive_audio () - выпущен GIL
(Новая тема) Цикл 0
Ошибка сегментации

код C следующим образом:

PyMODINIT_FUNC streamaudio() {
    PyObject *m = Py_InitModule("streamaudio", methods);
    PyEval_InitThreads();
    mainThreadState = PyThreadState_Get();
    PyEval_ReleaseLock();
    printf("(Main Thread) initmodule complete\n");
}

static PyObject* run_thread(PyObject* self, PyObject* args)
{
    int ok, stream_id;
    PyGILState_STATE gstate;
    gstate = PyGILState_Ensure();
    ok = PyArg_ParseTuple(args, "i", &stream_id);
    PyRun_SimpleString("print '(Main Thread) Creating thread'\n");
    int rc = pthread_create(&thread, NULL, receive_audio, (void*)stream_id);
    PyRun_SimpleString("print '(Main Thread) Thread created'\n");
    PyGILState_Release(gstate);
    return Py_BuildValue("i", rc);
}

void* receive_audio(void *x)
{
    printf("(New Thread) In receive_audio() - acquiring GIL\n");
    PyGILState_STATE gstate;
    gstate = PyGILState_Ensure();
    PyRun_SimpleString("print '(New Thread) python print!'\n");
    PyGILState_Release(gstate);
    printf("(New Thread) In receive_audio() - released GIL\n");
    int i;
    for (i = 0; i < 100; i++) {
    printf("(New Thread) Looping %d\n", i);
    sleep(1);
    }
}

1 Ответ

3 голосов
/ 19 марта 2010

Я не уверен, что это будет иметь отношение к вашему вопросу, но одна вещь, которая выглядит подозрительно, это вызов PyEval_ReleaseLock () в функции инициализатора вашего модуля. Я сомневаюсь, что Python ожидает, что ваш инициализатор модуля освободит GIL из-под него, и быстрый взгляд на пример кода здесь не показывает ничего подобного. Не могли бы вы удалить этот вызов PyEval_ReleaseLock () и рассказать нам, что происходит?

Кстати, я согласен, что вызовы PyGILState _ * () в run_thread () не должны иметь никакого эффекта; Вы должны быть в состоянии просто удалить их.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...