线程之间的线程通信
本文关键字:线程 通信 之间 | 更新日期: 2023-09-27 18:01:33
我有一个参数化的线程启动,初始化一些NAudio的东西…但我需要一个单独的线程告诉NAudio线程启动。当我尝试时,它崩溃了。如何实现安全的跨线程通信?
下面是线程(这个类成为主线程中的音频对象):
class Audio
{
public IWavePlayer OutDevice;
public WaveStream OutStream;
public Thread thread;
public Audio(string file)
{
this.thread = new Thread(new ParameterizedThreadStart(InitAudio)); thread.Start(file);
}
private void InitAudio(object data) {
this.OutDevice = new WaveOut();
this.OutStream = new WaveChannel32(new Mp3FileReader(data.ToString()));
this.OutDevice.Init(OutStream);
}
}
我需要能够有我的主线程调用audio.OutDevice.Play();但我不能,因为它是交叉线程的,它会崩溃。我该怎么做呢?
您的音频播放正在使用硬件资源,并且通常必须在创建它们的同一线程上访问这些资源。在您的代码中,您没有为线程上的持续访问留下任何空间。我很惊讶你听到了这段代码的声音,因为你自己的线程很快就会超出范围。只是因为你将这些变量绑定到类中,才会发生任何事情。我个人认为在这种情况下不需要单独的线程,因为我相信回放是或可以是非阻塞的。尽管如此,您仍然可以按照您的计划执行以下内容(伪代码):
public bool ShouldPlay;
private void InitAudio(object data) {
var OutDevice = new WaveOut();
var OutStream = new WaveChannel32(new Mp3FileReader(data.ToString()));
var OutDevice.Init(OutStream);
while(!_exitEvent.WaitOne(50ms)){
if(ShouldPlay && !OutDevice.IsPlaying)
OutDevice.Play();
else if(!ShouldPlay && OutDevice.IsPlaying)
OutDevice.Stop();
}
OutDevice.Stop();
OutDevice.Dispose();
OutStream.Dispose();
}
如果你想在后台线程中填充音频缓冲区,我建议使用WaveOutEvent类。这将创建它自己的背景线程,通过管道拉音频。然后可以在主线程中调用Play和Stop。在这种情况下,你需要注意的主要线程问题是,如果你需要在你正在播放的文件中实现重新定位,因为重新定位将发生在GUI线程上,而读取可能正在另一个线程上进行。
对于WinForms/WPF应用程序,最可靠的机制是使用WaveOut的windows消息回调(如果你在GUI线程上创建WaveOut,你会默认得到这个)。这避免了需要担心你在什么线程上重新定位。此外,通过使用GUI线程的一切,它避免了潜在的MTA和STA线程问题,如果你使用基于COM的API,如Windows Media API, MediaFoundation,或DirectX Media Object reampler,你会得到。