Я работаю над реализацией асинхронного воспроизведения звука для PyAudio .Бэкэнд Portaudio реализует асинхронное воспроизведение, создавая собственный поток и вызывая функцию C-callback всякий раз, когда ему нужны / есть новые аудиоданные.Всякий раз, когда вызывается эта функция C-callback, я вызываю ранее зарегистрированную функцию Python, где пользователь должен предоставить аудиоданные.
Поскольку этот вызов Python происходит в потоке, не созданном Python, документация говорит, что я должен позвонить PyGILState_Ensure()
до вызова Python и PyGILState_Release()
после этого.Примерно это выглядит так:
int stream_callback(const void *in, void* out, unsigned long frameCount,
const PaStreamCallbackTimeInfo *timeInfo,
PaStreamCallbackFlags statusFlags, void *userData)
{
PyGILState_STATE gstate = PyGILState_Ensure();
/* create some python variables, as used below… */
py_result = PyObject_CallFunctionObjArgs(py_callback,
py_frameCount,
py_inTime,
py_curTime,
py_outTime,
py_inputData,
NULL);
/* evaluate py_result, do some audio stuff… */
PyGILState_Release(gstate);
return returnVal;
}
Который segfaults в PyGILState_Release(gstate)
.Эта функция обратного вызова вызывается очень часто.Мол, от нескольких сотен до нескольких тысяч раз в секунду.gstate
является 32-битной переменной и иногда устанавливается на 1
, иногда на 0
на PyGILState_Ensure()
.Вылетает, только если установлено значение 1
.Обычно это один 1
, за которым следуют два-четыре 0
.
Такое ощущение, что PyGILState_Release(…)
занимает немного больше времени, чем фактическое возвращение, и, таким образом, вызывается во время работы или что-то в этом роде.
При сбое трассировка стека выглядит следующим образомэто:
#0 0x00007fff88c287b7 in pthread_mutex_lock ()
#1 0x00000001001009a6 in PyThread_release_lock ()
#2 0x00000001002efc82 in stream_callback (in=0x1014a4670, out=0x1014a4670, frameCount=4316612208, timeInfo=0x1014a4850, statusFlags=4297757032, userData=0x38) at _portaudiomodule.c:1554
#3 0x00000001004e3710 in AdaptingOutputOnlyProcess ()
#4 0x00000001004e454b in PaUtil_EndBufferProcessing ()
#5 0x00000001004e9665 in AudioIOProc ()
#6 0x00000001013485d0 in dyld_stub_strlen ()
#7 0x0000000101348194 in dyld_stub_strlen ()
#8 0x0000000101346523 in dyld_stub_strlen ()
#9 0x0000000101345870 in dyld_stub_strlen ()
#10 0x000000010134aceb in AUGenericOutputEntry ()
#11 0x00007fff88aa132d in HP_IOProc::Call ()
#12 0x00007fff88aa10ff in IOA_Device::CallIOProcs ()
#13 0x00007fff88aa0f35 in HP_IOThread::PerformIO ()
#14 0x00007fff88a9ef44 in HP_IOThread::WorkLoop ()
#15 0x00007fff88a9e817 in HP_IOThread::ThreadEntry ()
#16 0x00007fff88a9e745 in CAPThread::Entry ()
#17 0x00007fff88c5c536 in _pthread_start ()
#18 0x00007fff88c5c3e9 in thread_start ()
Имеет ли это смысл для кого-либо?