4

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

当一个音符正在播放时(作为枚举的一部分),我怎么能允许一个新的音符可能被添加到列表中(没有明显的集合修改例外)。

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

伪逻辑原样:

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 事件都会向队列添加一个注释,然后调用队列上的播放方法。

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

我希望我已经清楚地解释了我想要做什么?

4

3 回答 3

4

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

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 是线程安全的,因此不需要实现锁定。

于 2012-06-03T19:17:55.543 回答
0

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

于 2012-06-03T19:18:04.323 回答
0

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

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

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

于 2012-06-03T19:03:07.117 回答