【问题标题】:Buffer underrun logic problem, threading tutorial?缓冲区欠载逻辑问题,线程教程?
【发布时间】:2010-08-05 19:40:18
【问题描述】:

好的,我尝试了各种标题,但都失败了(所以如果有人想出更好的标题,请随时编辑:P)

我有以下问题:我正在使用 API 来访问我不编码的硬件,将库添加到我需要从 API 接口继承的 API,而 API 可以完成所有工作。

我把那个API,一个音乐生成器库,问题是提到的API只在缓冲区为空时调用音乐库,并要求硬编码的数据量(正好1024 * 16个样本......不知道为什么)。

这意味着音乐生成器库,无法使用所有 CPU 潜力,在播放音乐时,即使音乐库没有跟上,CPU 使用率仍然很低(如 3%),因此在部分音乐中,有太复杂的东西,缓冲区不足(即:声卡播放缓冲区中空的区域,因为音乐库函数还没有返回)。

调整硬编码的数字,只会使软件在某些机器上工作,而在其他机器上不工作,这取决于几个因素......

所以我想出了两个解决方案:用一些新的缓冲区逻辑来破解 API,但我没有想到这方面的任何东西。

或者我真正想到的逻辑:让音乐库有自己的线程,它将有自己的单独缓冲区,当 API 调用音乐库以获取更多数据时,它将一直填充,而不是生成时,它会将数据从单独的缓冲区复制到声卡缓冲区,然后继续生成音乐。

我的问题是虽然我有几年的编程经验,但我总是避免使用多线程,我什至不知道从哪里开始......

问题是:有人能找到另一个解决方案吗,或者指点我到一个地方,让我了解如何实施我的线程解决方案?

编辑:

我不是在阅读文件,而是在生成或计算音乐,明白吗?这不是 .wav 或 .ogg 库。这就是为什么我提到 CPU 时间,如果我可以使用 100% 的 CPU,我将永远不会出现欠载,但我只能在程序意识到缓冲区即将结束和实际结束之间的短时间内使用 CPU缓冲区,这个时间有时比程序计算音乐所用的时间少。

【问题讨论】:

  • Threading books for C++的可能重复
  • 每次 API 调用您的回调函数时,您是否从磁盘读取 (1024*16) 个字节?
  • @Hans 不重复,因为我不想要书,我有 2 天的时间来实现它:P 而且它并不复杂...... @tholomew 不,我正在生成 1024*16 字节,虽然当流式传输 .wav 文件时,API 确实从磁盘读取 1024*16 字节,但那部分与我无关......

标签: c++ multithreading buffering


【解决方案1】:

我相信使用单独线程为库准备数据以便在请求时准备好数据的解决方案是减少延迟和解决此问题的最佳方法。一个线程生成音乐数据并将其存储在缓冲区中,API 线程在需要时从该缓冲区获取数据。在这种情况下,无论您是读取还是写入,您都需要同步对缓冲区的访问,并确保在 API 太慢的情况下您没有太大的缓冲区。要实现这一点,您需要线程库中的一个线程、互斥体和条件原语以及两个标志 - 一个指示何时请求停止,另一个指示如果 API 无法跟上并且它变得太大,则要求线程暂停填充缓冲区。我建议使用 C++ 的 Boost Thread 库,这里有一些有用的文章以及我想到的示例:

【讨论】:

  • 很遗憾你的回复来不及了,我已经实现了pthread解决方案……不过还是不错的回复
【解决方案2】:

您不一定需要一个新线程来解决这个问题。您的操作系统可能会提供异步读取操作;例如,在 Windows 上,您可以使用 FILE_FLAG_OVERLAPPED 打开文件以对其进行异步操作。

如果您的操作系统确实支持此功能,您可以创建一个大缓冲区来保存几个调用的数据。当应用程序启动时,您填充缓冲区,然后一旦它被填充,您就可以将缓冲区的第一部分传递给 API。当 API 返回时,您可以读入更多数据以覆盖上次 API 调用使用的缓冲区部分。因为读取是异步的,所以它会在 API 播放音乐时填充缓冲区。

实现可能比这更复杂,即使用循环缓冲区或等到几个部分已被消耗,然后一次读取多个部分,而不是一次读取一个部分。

【讨论】:

  • 好主意,要是这个 API 支持异步 I/O 就好了。
猜你喜欢
  • 2015-10-19
  • 2018-03-08
  • 2012-09-13
  • 1970-01-01
  • 1970-01-01
  • 2023-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多