C++ XAudio2教程-分离线程和异步读取?

C++ XAudio2教程-分离线程和异步读取?,c++,windows,multithreading,asynchronous,xaudio2,C++,Windows,Multithreading,Asynchronous,Xaudio2,我以前使用过这个XAudio2流媒体教程,成功地创建了一个从磁盘()流媒体播放音频的程序 现在我正在重新编写代码,一些奇怪的事情在我看来很突出。他们创建一个单独的线程,从文件中读取小块音频数据,并将这些小块提交到语音缓冲区。很好,现在主线程可以在音频播放时执行任何需要的操作,但是为什么还要在流线程中使用异步文件读取呢?据我所知,每次循环迭代都会执行一次文件读取,线程会立即等待,直到区块被完全读取,然后再将其提交到语音缓冲区 他们所做的有什么优势还是没有必要?XAudio2示例代码使用“异步”而不

我以前使用过这个XAudio2流媒体教程,成功地创建了一个从磁盘()流媒体播放音频的程序

现在我正在重新编写代码,一些奇怪的事情在我看来很突出。他们创建一个单独的线程,从文件中读取小块音频数据,并将这些小块提交到语音缓冲区。很好,现在主线程可以在音频播放时执行任何需要的操作,但是为什么还要在流线程中使用异步文件读取呢?据我所知,每次循环迭代都会执行一次文件读取,线程会立即等待,直到区块被完全读取,然后再将其提交到语音缓冲区


他们所做的有什么优势还是没有必要?

XAudio2示例代码使用“异步”而不是“阻塞”I/O的原因是最佳实践。之所以在“工作线程”中执行,主要是为了简单,因为在游戏中,音频通常由自己的线程处理,以避免出现故障并保持渲染/更新循环的独特性

您可以将async/submit作为
Update
循环的一部分来处理,但前提是您必须确保它始终能够得到足够快的处理,以避免出现故障。事实上,这就是我在上使用最新的旧版DirectX SDK版本的XAudio2流媒体示例时所采用的方法

更奇特的实现可以使用
ReadFileEx
,但工作线程方法更简单。另外,由于在Windows 8中如何实现API分区的一些怪癖,
ReadFileEx
在Windows应用商店平台/Windows phone 8/UWP上不受支持,因此教程/示例避免了它,以免将您指向不适用于所有Microsoft平台的方向。FWIW、
ReadFileEx
writefilex
在Windows 10周年更新(14393)中被添加回UWP

注意:在使用重叠I/O等待的事件中,在如何处理
错误\u IO\u挂起
场景方面存在一些怪癖。这在Windows 8或更高版本中通过
GetOverlappedResultEx
函数得到改进和简化。对于我在中的wave bank reader,我使用此模式为较旧和较新的平台构建:

bool wait = false;
if( !ReadFile( hFile.get(), &m_data, sizeof( m_data ), nullptr, &request ) )
{
    DWORD error = GetLastError();

    if ( error != ERROR_IO_PENDING )
        return HRESULT_FROM_WIN32( error );

    wait = true;
}

#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
result = GetOverlappedResultEx( hFile.get(), &request, &bytes, INFINITE, FALSE );
#else
if ( wait )
    (void)WaitForSingleObject( m_event.get(), INFINITE );

result = GetOverlappedResult( hFile.get(), &request, &bytes, FALSE );
#endif

if ( !result || ( bytes != sizeof( m_data ) ) )
{
    return HRESULT_FROM_WIN32( GetLastError() );
}

是的,使用ReadFile然后立即转到GetOverlappedResult似乎有点奇怪。就我个人而言,我更喜欢带有APC的ReadFileEx,并让我的消息循环围绕MsgWaitForMultipleObjectsEx构建,以便它在通知消息准备就绪的同时执行可警报的等待。这样,这种I/O甚至不需要第二个线程。这是一种处理流音频的有趣方式。在您回复之前不久,我能够在辅助线程中处理同步文件读取,没有任何问题,所以我想这两种方式都可以,只是在教程中是多余的。通过使用不同的实现方法(单线程异步/多线程同步),我更清楚地看到了它们的优点和缺点。上面的代码是从“音频工作线程”调用的,因此它可以阻止等待加载。从主线程开始可能不是一个好主意,除非这就是你正在做的。请注意,此特定代码在示例中使用。它实际上不是流式代码,但它确实使用异步I/O。我想如果我的项目需要,我会更深入地研究这个问题,但我相信我现在已经找到了需要的答案。