【发布时间】:2011-07-05 16:31:38
【问题描述】:
我正在为PyAudio 实现异步音频播放。后端 Portaudio 通过创建自己的线程并在需要/有新音频数据时调用 C 回调函数来实现异步播放。每当调用该 C 回调函数时,我都会调用以前注册的 Python 函数,用户必须在其中提供音频数据。
由于对 Python 的调用发生在非 Python 创建的线程中,the documentation 表示我必须在调用 Python 之前调用 PyGILState_Ensure(),之后调用 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 位变量,有时由PyGILState_Ensure() 设置为1,有时设置为0。只有在设置为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 ()
这对任何人都有意义吗?
【问题讨论】:
-
您链接的问题与 PyEval_ReleaseLock 永远不是正确的调用方式有关(它已被弃用),因此这不太可能是您的问题。你能在调试器中准确地看到 PyGILState_Release 发生段错误的位置吗? gstate 值为 1 表示调用来自非 Python 线程,因此临时线程状态实际上正在被销毁,并且可能会发生很多事情。
-
另外,您链接的是哪个版本? (GIL 代码在 3.2 中发生了相当大的变化,所以我看哪个版本会有所不同)
-
我正在使用 Python 2.7.1 OSX
标签: python multithreading callback segmentation-fault portaudio