1. 程式人生 > >waveInReset/waveOutReset死鎖原因與解決方案

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