C#锁定导致冻结
本文关键字:冻结 锁定 | 更新日期: 2023-09-27 18:21:43
我有这个声音列表:
List<SourceVoice> runningInstances;
我将一个事件附加到一个声音对象,以便在它停止时将其从列表中删除。
sourceVoice.StreamEnd += delegate
{
lock (runningInstances)
{
runningInstances.Remove(sourceVoice);
}
};
我还有一个stop函数,它可以从任何线程调用。
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();
}
}
我认为,由于我将事件作为委托,它将一直等到对象解锁。然而,它似乎冻结在那里。
有两种可能性:
-
在与CCD_ 1相同的线程上引发该事件。
lock() {}
没有任何功能,因为它是可重入的,但它也是无害的。调用Clear()时,这些项应该已经被删除。 -
在另一个(线程池)线程上引发该事件。这取决于
sourceVoice.Stop()
。lock()
将阻止事件处理,直到runningInstances.Clear()
之后。之后,处理程序将运行,从eptyList<>
中删除不会出错。
两者都不会导致任何"冻结",所以代码中一定有我们看不到的相关内容。
委托只是回调,它们对线程没有任何保证。您可能想要签出ConcurrentBag类,它已经是线程安全的,这样就可以避免对集合的锁定过于担心。
看起来stop方法的锁定范围内的一个调用可能导致触发StreamEnd事件。您可以通过遍历stop方法中的代码来测试这一点,看看它是否跳到事件中。我大胆猜测这是sourceVoice.Stop()调用。
如果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(),您可以查看
ToList()--它是否创建一个新列表?