我正在编写一个音频应用程序,它有多个线程产生声音,一个线程混合声音并将它们发送到声卡。我已经尝试了几种同步线程的方法,包括信号和线程安全队列在内的“正确”方式,但它们都太慢了。所以现在我为每个生产者使用bool来指示它的队列是否已满。它似乎工作得很好(32个线程的延迟为5ms),但这样做是否安全?
class PlayThreadParameters
{
public Queue<Samples> queue;
public bool isOutputQueueFull;
}
制作人看起来像这样:
public void PolyPlayThread(object o)
{
var playThreadParameters = (PlayThreadParameters)o;
while (isPlaying)
{
while (playThreadParameters.isOutputQueueFull)
{
if (!isPlaying)
return;
Thread.Sleep(1);
}
... //fill output queue
playThreadParameters.isOutputQueueFull = true;
}
}
消费者看起来像这样(由Naudio从一个单独的线程调用):
public override int Read(byte[] array, int offset, int count)
{
for (int v = 0; v < playThreadParameters.Length; v++)
while (!playThreadParameters[v].isOutputQueueFull)
{
if (!isPlaying)
return 0;
Thread.Sleep(1);
}
... //mix the samples from the outputqueues
for (int v = 0; v < playThreadParameters.Length; v++)
playThreadParameters[v].isOutputQueueFull =false;
return count;
}
答案 0 :(得分:5)
据我所知,.NET内存模型并不能保证在一个线程中生成的变量的更改在另一个线程中可见。那里需要一个内存barrier。最简单(但不是最有效)的方法是使用lock
或Interlocked
方法进行整理。
顺便说一句,忙碌的等待并不是实现目标的最佳方法。也许你想用适当的条件变量(C#parlance中的Monitor
)用法切换到producer-consumer model?
答案 1 :(得分:4)
不,这不是完全安全的,但大多数时候你可能会幸运;-)你应该使用Interlocked方法来访问bool。