В этом случае идеально подойдет очень простая очередь производителя / потребителя - поскольку у вас есть только 1 производитель и 1 потребитель, вы можете сделать это с минимальной блокировкой.
Не используйте критическую секцию (оператор lock
) вокруг фактического метода / операции Play
, как предлагают некоторые люди, вы можете очень легко получить конвой с замком . Вам действительно нужно заблокировать, но вы должны делать это только в течение очень коротких периодов времени, а не во время воспроизведения звука, что является вечностью в компьютерном времени.
Примерно так:
public class SoundPlayer : IDisposable
{
private int maxSize;
private Queue<Sound> sounds = new Queue<Sound>(maxSize);
private object sync = new Object();
private Thread playThread;
private bool isTerminated;
public SoundPlayer(int maxSize)
{
if (maxSize < 1)
throw new ArgumentOutOfRangeException("maxSize", maxSize,
"Value must be > 1.");
this.maxSize = maxSize;
this.sounds = new Queue<Sound>();
this.playThread = new Thread(new ThreadStart(ThreadPlay));
this.playThread.Start();
}
public void Dispose()
{
isTerminated = true;
lock (sync)
{
Monitor.PulseAll(sync);
}
playThread.Join();
}
public void Play(Sound sound)
{
lock (sync)
{
if (sounds.Count == maxSize)
{
return; // Or throw exception, or block
}
sounds.Enqueue(sound);
Monitor.PulseAll(sync);
}
}
private void PlayInternal(Sound sound)
{
// Actually play the sound here
}
private void ThreadPlay()
{
while (true)
{
lock (sync)
{
while (!isTerminated && (sounds.Count == 0))
Monitor.Wait(sync);
if (isTerminated)
{
return;
}
Sound sound = sounds.Dequeue();
Play(sound);
}
}
}
}
Это позволит вам ограничить количество воспроизводимых звуков, установив maxSize
на некоторый разумный предел, например 5, после которого он будет просто отбрасывать новые запросы. Причина, по которой я использую Thread
вместо ThreadPool
, заключается в простом поддержании ссылки на управляемый поток и возможности надлежащей очистки.
При этом используется только один поток и одна блокировка, поэтому у вас никогда не будет конвой блокировки и никогда не будут воспроизводиться звуки одновременно.
Если у вас возникли проблемы с пониманием этого или вам нужно больше подробностей, взгляните на Threading в C # и перейдите к разделу «Очередь производителя / потребителя».