注册账号 登陆地址 QQ:7159350

当前位置是:主页 > 娱乐动态 >

waveOutReset的N种死法, 及其解决方案

来源:首页-万达娱乐【集团】注册中心_万达招商政策平台 发布时间:2019-04-15

  我遭遇到了调用waveOutReset死锁的问题,在GOOGLE上一搜,遇到同样问题的人还真不少,但没有人很明确地找到造成DEADLOCK的原因,都是糊里糊涂就把问题解决了,然后把运行OK的代码一贴完事。我花了四五个小时才彻底摸清楚规律,把这经验拿出来共享

  原则:

  (1) waveOutReset不是立即返回的函数, 而需要等待驻留在WAVEDEV里的音频BUFFER全部标记为WOM_DONE,经过callback proc处理完毕后, waveOutReset才会返回.

  (2) 在waveOutReset调用到返回之间的这段时间内, 禁止任何线程对处于reset中的HWAVEOUT调用任何WAVE API, 否则立刻造成死锁.

  把握住这两个原则就可以根治waveOutReset死锁问题了. 不过为了把事情描述得更具体些, 我把网上多数人造成死锁的情况列一下, 并给出解决方法

  第一种死法:

  在回调处理函数WaveCallbackFunc中,对标记为WOM_DONE的BUFFER进行waveOutUnprepareHeader

  错误分析:

  调用waveOutReset后, 系统内所有未播放的buffer全部被标记为WOM_DONE返回给WaveCallbackFunc, 这属于waveOurReset处理过程的一部分, 此时waveOurReset还未返回. 所以这时如果调用到waveOutUnprepareHeader, 就会立刻造成死锁. 我自己也是犯的这个错误。

  解决方法:

  在调用waveOurReset之前设置一个FLAG, 然后在WaveCallbackFunc里要调用waveOutUnprepareHeader之前判断一下这个FLAG, 如果处于reset过程中就跳过waveOutUnprepareHeader. 范例代码:

  static CRITICAL_SECTION g_CS;

  static BOOL g_bResetting=FALSE;

  void Reset()

  {

  ? EnterCriticalSection(&g_CS);? //之前InitializeCriticalSection一下

  ? g_bResetting=TRUE;

  ? LeaveCriticalSection(&g_CS);

  ?

  ? waveOutReset();

  ? g_bResetting=FALSE;? //万达娱乐RESET后就不会调WaveCallbackFunc了,所以不需要锁

  }

  VOID CALLBACK WaveCallbackFunc(HWAVEOUT hwo, UINT32 uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)

  {

   EnterCriticalSection(&g_CS); //防止g_bResetting在if判断之后, waveOutUnprepareHeader之前被设成1了, callback和reset处于不同线程

  ?

  ? if( (uMsg==WOM_DONE) && !g_bResetting )

  ? {

  ? waveOutUnprepareHeader(hWaveOut, pWaveHdr, sizeof(WAVEHDR));

  ? }

  ?

  ? LeaveCriticalSection(&g_CS);

  }

  ?

  另外, 如果使用了每个BUFFER定长的BUFFER-CHAIN来做生产者-消费者模型, 那么在BUFFER-CHAIN初始化的时候顺便把所有WAVEHDR都PREPARE好, 而只在BUFFER-CHAIN全部释放的时候才做UNPREPARE, 那么在每次waveOutWrite和WOM_DONE的循环里就不需要PREPARE/UNPREPARE了,这也能避开上述情况造成的死锁

  第二种死法: 某些人喜欢在在回调处理函数WaveCallbackFunc中,调用waveOutWrite往系统里填充新BUFFER.

  错误分析: 同情况一, 万达娱乐 在waveOutReset过程中,如果WaveCallbackFunc调用了waveOutWrite, 同样会造成死锁.

  解决方法: 同情况一, 设置FLAG和临界区配合来防止. 不过比较建议在另外的线程中调waveOutWrite写入BUFFER, 这才符合生产-消费模型.

  第三种死法: 在另外一个线程中调用waveOurWrite, 但是waveOutReset之前, 没有停下那个线程

  错误分析: RESET过程中,还有waveOurWrite调用

  解决方法: 把waveOurWrite那个线程suspend或退出, 或者在waveOutWrite前面用FLAG+临界区判断

  第四种死法: 也是最匪夷所思的死法, 从UI的某个按钮一路调用到waveOutReset(处于同线程中),? 而在WaveCallbackFunc中,同线程调用SetWindowText之类UI函数

  错误分析:? 事实是:

  (1) 如果是在WindowProc的某个CASE里调用SetWindowText, 调用者和SetWindowText处于同线程中,那么运行正常, 多数UI也都会这么写;

  (2) 如果处于Thread1的UI调用了waveOutReset, 导致处于Thread2中的WaveCallbackFunc运行并调用SetWindowText, 试图设置处于Thread1的UIcallbackProc, 那么SetWindowText会死锁, 导致WaveCallbackFunc死掉, 最后表面上看起来就是waveOutReset死掉.其实我也不明白为什么这样也能死,要问就去问盖茨大叔吧.

  解决方法:

  在WaveCallbackFunc中,用RESET FLAG + 临界区的方法保护UI调用函数, 使其在waveOutReset过程中不被调用, 或者用PostMessage这样的异步函数,实在不得不同步影响UI的话就忍一忍等waveOurReset函数返回后再做吧.

  ?

  本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/renjwjx/archive/2009/03/03/3954012.aspx


万达娱乐: http://thailand-beauty.com/



上一篇:李白_1

下一篇:没有了