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

C# 如何在执行枚举时管理更改列表?,c#,multithreading,list,enumeration,C#,Multithreading,List,Enumeration,我有一个对象(音符)列表,当它们播放时,在单独的线程上枚举。我这样做是为了让UI线程保持响应性 当一个音符播放时(作为枚举的一部分),我如何允许将一个新音符添加到列表中(没有明显的集合修改异常) 我知道我可以将列表复制到一个临时列表中并列举出来,但我实际上希望随着用户选择更多的列表而增长(这将在播放第一个音符时发生) psuedo逻辑原样: onClick() { Queue.Add(theClickedNote) Queue.Play() <-- on another thread

我有一个对象(音符)列表,当它们播放时,在单独的线程上枚举。我这样做是为了让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);
 }
}
onClick()
{
添加(单击注释)

Queue.Play()您应该使用真实的队列,而不是使用列表 那么您的代码将如下所示:

    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();
        }
    }
Queue Queue=new Queue();
void onClick()
{
排队。排队(注);
}
无效播放()
{
如果(Playing==true){return;}
while(queue.Peek()!=null)
{
var note=queue.Dequeue();
注:play();
}
}

此代码不是线程安全的,因此您应该在队列上添加锁,但这是一般的想法。

类似的内容可以与.Net 4中的
ConcurrentQueue一起使用

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=new ConcurrentQueue();
void onClick()
{
Queue.Enqueue(点击注释);
//如有必要,在另一个线程上开始播放
}
无效播放()
{
如果(玩)回来;
注释;
while(Queue.TryDequeue(out note))
{
注:Play();
}
}

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

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

队列是
列表
还是
队列
?看起来像
列表
,但您的变量名称很混乱,并且只显示伪代码。…对不起,有很多代码,因此psuedo,队列是一个列表…我敢问什么是队列,而不用谷歌你要找的是
生产者和消费者
模式…@DanielGwalter不枚举队列。只需依次将每个项目出列。如果可以使用.Net 4,请查看ConcurrentQueue。@Mikez with ConcurrentQueue我可以在枚举时添加到它吗?
Peek
如果队列为空,则抛出。您应该检查计数。这完成了任务,如果您有时间,您可以在上面的示例中向我展示一下锁的情况吗…(锁对我来说是新的)mike z使用ConcurrentQueue有更好的解决方案,因为它是线程安全的。如果您想给我的解决方案添加锁,只需在queue.enqueue和queue.dequeue方法调用周围加一个锁(queue)块。它看起来类似于锁(queue){queue.enqueue(note);}