线程之间的线程通信

本文关键字:线程 通信 之间 | 更新日期: 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,你会得到。