我有这个声音列表:
List<SourceVoice> runningInstances;
我将一个事件附加到声音对象,以便在停止时将其从列表中删除。
sourceVoice.StreamEnd += delegate
{
lock (runningInstances)
{
runningInstances.Remove(sourceVoice);
}
};
我也有这个停止功能,可以从任何线程调用。
public void stop(int fadeoutTime)
{
lock (runningInstances)
{
foreach (var sourceVoice in runningInstances)
{
if (!sourceVoice.IsDisposed)
{
sourceVoice.Stop();
sourceVoice.FlushSourceBuffers();
sourceVoice.DestroyVoice();
sourceVoice.Dispose();
}
}
runningInstances.Clear();
}
}
我认为,因为我将事件作为委托,所以它将一直等到对象被解锁。但似乎它冻结在那里。
答案 0 :(得分:2)
有两种可能性:
事件在与sourceVoice.Stop();
相同的线程上引发。 lock() {}
没有任何功能,因为它是可重入的,但它也是无害的。调用Clear()时,应该已经删除了Items。
该事件在另一个(线程池)线程上引发。这最多为sourceVoice.Stop()
。 lock()
将阻止事件处理,直到runningInstances.Clear()
之后。之后处理程序将运行并从epty List<>
中删除不是错误。
两者都不会导致任何“冻结”,因此在我们看不到的代码中必须存在相关内容。
答案 1 :(得分:-1)
代表只是回调,他们不对线程做出任何保证。您可能想要查看已经是线程安全的ConcurrentBag class,这样您就可以避免担心与集合相关的锁定。
答案 2 :(得分:-2)
看起来停止方法锁定范围内的其中一个调用可能会导致 StreamEnd 事件触发。您可以通过单步执行停止方法中的代码来查看是否跳转到事件中。我猜测它是 sourceVoice.Stop()调用。
答案 3 :(得分:-2)
如果sourceVoice.Stop()
始终提升sourceVoice.StreamEnd
事件,您可以按以下方式更改停止方式。
public void stop(int fadeoutTime)
{
foreach (var sourceVoice in runningInstances.ToList<SourceVoice>())
{
if (!sourceVoice.IsDisposed)
{
sourceVoice.Stop();
sourceVoice.FlushSourceBuffers();
sourceVoice.DestroyVoice();
sourceVoice.Dispose();
}
}
}
要了解.ToList(),您可以看到