2013-02-21 4 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의 값이 변경되었습니다.