我正在为PyAudio实现异步音频播放。后端 Portaudio 通过创建自己的线程并在需要/有新音频数据时调用 C 回调函数来实现异步播放。每当调用 C 回调函数时,我都会调用先前注册的 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;
}
哪个段错误PyGILState_Release(gstate)
。这个回调函数经常被调用。比如,每秒几百到几千次。这gstate
是一个 32 位变量,有时设置为1
,有时设置为0
by PyGILState_Ensure()
。它仅在设置为 时崩溃1
。通常,会有 11
后跟 2 到 4 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 ()
这对任何人都有意义吗?