c# - 在队列中播放 .wav 文件

标签 c# .net multithreading queue wav

尝试在线程安全队列中播放 .wav 文件。任何线程都可以随机触发调用,但必须按顺序播放。问题是当我调用 Play(string[] files)假设有 3 个文件名(目前正在从 UI 线程测试),最后一个文件播放了 3 次,而第一个文件从未播放过。看不出这是什么原因造成的..?

希望提供更简单的方法来执行此操作,但主要想知道为什么这不起作用。

public class Audio
{
    static ActionQueue actionQueue;
    public static string MediaFolder { get; set; }
    private static object syncroot = new object();

    static Audio()
    {
        actionQueue = new ActionQueue();
    }

    /// <summary>
    /// Plays .wav in async queue. 
    /// </summary>
    /// <param name="fileName"></param>
    public static void Play(string fileName)
    { 
        actionQueue.Add(() => PlaySound(fileName));
    }

    public static void Play(string[] files)
    {
        Console.WriteLine("ID0: " + Thread.CurrentThread.ManagedThreadId);
        foreach (string f in files.ToList())
        {
            Console.WriteLine("Queue file: " + f);
            actionQueue.Add(() => PlaySound(f));
        }
    }

    private static void PlaySound(string f)
    {
        Console.WriteLine("ID1: " + Thread.CurrentThread.ManagedThreadId);

        var fileName = f;

        Console.WriteLine("Play queue: " + fileName);

        fileName = Path.Combine(MediaFolder, fileName);

        if (!Path.HasExtension(fileName))
            fileName = fileName + ".wav";

        if (!File.Exists(fileName)) return;
        string ext = Path.GetExtension(fileName);
        if (ext != ".wav") return;

        Console.WriteLine("Playing: " + fileName);

        SoundPlayer player = new SoundPlayer(fileName);
        player.PlaySync();
    }
}

public class ActionQueue
{
    private  BlockingCollection<Action> persisterQueue = new BlockingCollection<Action>();     

    public  ActionQueue( )
    { 
        var thread = new Thread(ProcessWorkQueue);
        thread.IsBackground = true;
        thread.Start();
    }

    private   void ProcessWorkQueue()
    {
        while (true)
        {
            var nextWork = persisterQueue.Take(); 
            nextWork();  
        }
    }

    public  void Add(Action action)
    { 
        persisterQueue.Add(action ); 
    }
}

最佳答案

经典captured-loop-variable-in-a-closure问题。

您需要复制循环变量,即

    foreach (string f in files.ToList())
    {
        var copy = f;
        Console.WriteLine("Queue file: " + f);
        actionQueue.Add(() => PlaySound(copy));
    }

原因是您的代表被传递给 actionQueue在循环完成之前不会执行。当然,到那个时候,变量 f已经改变了值(value)。

关于c# - 在队列中播放 .wav 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15006698/

相关文章:

c# - 使用 C# 从 SQL 显示和保存 "time"数据类型?

c# - 动画列表框中的已删除项目

c# - Web API 中的手动模型验证

c# - 为什么我在打开连接时收到 "Invalid attempt to call HasRows when reader is closed"?

c# - 当用户在主线程中处理对象时在后台线程中处理对象

c# - ASP.NET MVC - 在默认帐户系统中删除用户?

C# 组合类/模型或创建具有继承的多个类

c# - dotnet 和 msbuild 中的包之间的区别

java - 组合多个接收源

python - 在按下的每个键上实现自动建议