waveInReset/waveOutReset死鎖原因與解決方案
問題背景
錄音播音實際需求
1、隨時終止
2、錄音並非檔案,而是形成rtp傳送
3、播音並非源於檔案,而是源於rtp
因此Waveform audio使用的buffer較小,不斷的裝載/傳送 buffer,終止的時候Reset並且close.
大致如下呼叫的迴圈
錄音
waveInUnprepareHeader
waveInPrepareHeader
waveInAddBuffer
播音
waveOutUnprepareHeader
waveOutPrepareHeader
waveOutWrite
迴圈週期40ms,我採用的是回撥函式。問題是有時候呼叫waveInReset/waveOutReset會形成死鎖,呼叫waveInReset/waveOutReset的執行緒與回撥函式所在的執行緒死鎖在一塊了。
原因分析
這方面網上有文章提到,就是呼叫waveInReset/waveOutReset的同時呼叫了錄音/播音迴圈呼叫的某個函式會形成死鎖。我再稍作解釋下,我們知道buffer滿了或是呼叫Reset都會觸發訊息(回撥函式方式的話就是MM_WOM_DONE/MM_WIM_DATA),由於呼叫waveInReset/waveOutReset所在的執行緒,與回撥函式所在的執行緒不是一個執行緒,因此很容易撞車,也就是說,你呼叫reset的時候,另一個執行緒正好在處理MM_WOM_DONE/MM_WIM_DATA,於是就這樣死鎖了。
解決方案
方案一
先加上標記(假設標記bReset:bool),令bReset為true;
標記作用如下
if(!bReset)
{
錄音
waveInUnprepareHeader
waveInPrepareHeader
waveInAddBuffer
播音
waveOutUnprepareHeader
waveOutPrepareHeader
waveOutWrite
}
延時呼叫waveInReset/waveOutReset,延時時間長度以迴圈週期為妙,我這個例子中也就是採用40ms。
當然也可以採用臨界保護。
方案二
換一個角度去考慮問題,之所以死鎖,是因為兩個執行緒衝突了的緣故,所以可以建立一個執行緒
錄音
waveInUnprepareHeader
waveInPrepareHeader
waveInAddBuffer
播音
waveOutUnprepareHeader
waveOutPrepareHeader
waveOutWrite
與waveInReset/waveOutReset都放到這個執行緒去處理,自然不會發生死鎖了。
update by sld 2010-3-8