C#lock导致冻结

时间:2013-07-09 12:59:22

标签: c# mutex deadlock xaudio2

我有这个声音列表:

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

我认为,因为我将事件作为委托,所以它将一直等到对象被解锁。但似乎它冻结在那里。

4 个答案:

答案 0 :(得分:2)

有两种可能性:

  1. 事件在与sourceVoice.Stop();相同的线程上引发。 lock() {}没有任何功能,因为它是可重入的,但它也是无害的。调用Clear()时,应该已经删除了Items。

  2. 该事件在另一个(线程池)线程上引发。这最多为sourceVoice.Stop()lock()将阻止事件处理,直到runningInstances.Clear()之后。之后处理程序将运行并从epty List<>中删除不是错误。

  3. 两者都不会导致任何“冻结”,因此在我们看不到的代码中必须存在相关内容。

答案 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(),您可以看到

ToList()-- Does it Create a New List?