如何在执行枚举时管理更改列表?

时间:2012-06-03 18:31:20

标签: c# multithreading list enumeration

我有一个对象列表(音符),它们在播放时在单独的线程上枚举。我这样做是为了让我可以保持UI线程的响应。

虽然正在播放音符(作为枚举的一部分),但我如何允许将新音符添加到列表中(没有明显的集合修改例外)。

我知道我可以将列表复制到临时列表并枚举,但我实际上希望列表随着用户选择更多而增长(这将在第一个音符播放时发生等)。

psuedo逻辑原样:

onClick()
{
 Queue.Add(theClickedNote)
 Queue.Play() <-- on another thread
}

Play()
{
 if(Playing==true){return ;}

 foreach(note theNote in Queue)
 {
  Note.Play();
  Queue.Remove(theNote);
 }
}

正如您在上面所看到的,每个Click事件都会向Queue添加一个注释,然后在队列中调用play方法。

队列枚举笔记并在删除笔记之前依次播放每个笔记

我希望我已经解释了我想要做的事情吗?

3 个答案:

答案 0 :(得分:4)

这样的东西可以与.Net 4中的ConcurrentQueue<T>一起使用。

ConcurrentQueue<Note> Queue = new ConcurrentQueue<Note>();

void onClick()
{
  Queue.Enqueue(theClickedNote);

  // start Play on another thread if necessary
}

void Play()
{
  if (Playing) return;

  Note note;
  while(Queue.TryDequeue(out note))
  {
     note.Play();
  }
}

ConcurrentQueue是线程安全的,因此不需要实现锁定。

答案 1 :(得分:0)

您应该使用真实的队列,而不是使用List 然后你的代码将如下所示:

    Queue<Note> queue = new Queue<Note>();
    void onClick()
    {
        queue.Enqueue(note);
    }

    void Play()
    {
        if (Playing == true) { return; }

        while (queue.Peek() != null)
        {
            var note = queue.Dequeue();
            note.play();
        }
    }

这段代码不是线程安全的,所以你应该在队列上添加锁,但这是一般的想法。

答案 2 :(得分:0)

正如mike z所建议的那样,使用.NET 4.0中添加的ConcurrentQueue
与其他并发集合一起,此队列允许您异步添加/删除项目+使用基础集合的快照,使用GetEnumerator方法并使用它进行迭代。 请注意,您仍然可能需要处理不同的情况,例如队列为空,这可以通过BlockingCollection来解决,只要集合为空,take方法就会阻塞线程