2013-02-21 91 views
1

嘗試在線程安全隊列中播放.wav文件。任何線程都可以隨機觸發通話,但必須依次播放。問題出在我打電話給Play(string[] files)說3個文件名(目前正在UI線程中測試),最後一個文件播放了3次,而第一個文件沒有播放過。看不到這是什麼原因..?播放隊列中的.wav文件

希望能有更簡單的方法來解決這個問題,但主要想知道爲什麼這樣做不起作用。

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); 
    } 
} 

回答

3

這是典型的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已經改變了價值。