3

我找不到任何有关 waveOut API 的线程安全的信息。

在我创建新的 waveOut 句柄后,我有这些线程:

线程 1:缓冲区处理。使用这些 API 函数:

  • waveOutPrepareHeader
  • waveOutWrite
  • waveOutUnprepareHeader

线程 2: Gui,控制器线程。使用这些 API 函数:

  • waveOutPause
  • waveOutRestart
  • waveOutReset
  • waveOutBreakLoop

这两个线程在同时使用相同的 waveOut 句柄时运行。在我的测试中,我没有发现该功能有任何问题,但这并不意味着它是安全的。

这种架构是线程安全的吗?是否有任何关于 waveOut API 的线程安全的文档?关于 waveOut API 线程安全的任何其他建议?

谢谢。

4

4 回答 4

4

一般来说,waveOut API 应该是线程安全的。因为通常 waveOutOpen() 会创建自己的线程,并且所有 waveOut* 函数都会向该线程发送消息。但是我不能给你证据...

但是,您可以更改您的应用程序以使其在任何情况下都安全:

  1. 启动你的线程进行缓冲区管理,记住 dwBufferThreadId
  2. 从 GUI 线程调用waveOutOpen,dwCallback设置为 dwBufferThreadId,fdwOpen 设置为 CALLBACK_THREAD
  3. 您的缓冲区管理线程:“waveOutWrite”提前一些缓冲区,GetMessage() 上的循环
  4. 每当缓冲区完成并且需要新缓冲区时,waveOutOpen 将发送 WOM_DONE,这是从该线程内 waveOutWrite 新缓冲区的时刻
  5. 从 GUI 线程调用 waveOutPause、waveOutRestart 等(MSDN 中没有任何内容反对它,所有示例都这样做,即使缓冲区将从另一个线程填充)

示例 1

如果您想 100% 确定,您可以获取一条 Windows 消息 (WM_USER+0),然后调用PostThreadMessage( WM_USER+0, dwBufferThreadId, MY_CTL_PAUSE,0 ),然后在您的缓冲线程中接收到该消息后,您就可以调用waveOutPause()那里。Windows 消息队列为您节省一些编写自己的消息队列的工作;-)

于 2009-12-14T19:51:00.870 回答
2

可悲的是,即使在单线程环境中也不安全。看这个问题进行讨论:

为什么 waveOutWrite() 会在调试堆中导致异常?

尝试将此报告给 Microsoft 导致他们关闭了该错误。他们不会修复它。

于 2009-12-18T12:15:11.463 回答
2

我也没有看到任何文档,但我无法想象对 waveOutWrite 的调用会被认为可以安全地与在同一句柄上对 WaveOutRestart 的调用同时运行。

如果您使用的是 VS2010 Beta2,我会查看Agents Library的各种演练并尝试将其转变为生产者消费者问题,您可以在其中传递诸如写入、暂停、重新启动等消息。

如果您没有使用 Visual Studio 2010(或不能),我会鼓励您找到一种方法,使用线程和某种存储要处理的命令的内部同步队列将其分解为生产者消费者问题。如果消息不是那么频繁,并且考虑到您只有 2 个线程在此队列上工作,那么您可以在 std::queue 周围放置一个普通的旧 Win32 关键部分...

希望这可以帮助。

于 2009-12-10T06:30:17.410 回答
1

它可能是线程安全的,但如果您(或我)找不到任何说明它是线程安全的官方文档,那么假设它不是并添加您自己的线程同步。一个轻量级的 EnterCriticalSection / LeaveCriticalSection 实现可能不超过十几行代码。

再多的测试都无法保证 API 是线程安全的:问题可能只发生在具有某些 CPU 或总线速度或某些声卡的某些架构上。您(或 Microsoft)都没有能力测试所有可能的配置。

您也不应该对 Microsoft 或 Intel 或声卡制造商或驱动程序编写者将在未来的某些实施中做什么做出任何假设。

于 2009-12-16T01:28:41.180 回答