-1

我有这个声音列表:

     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

4 回答 4

2

有2种可能:

  1. 该事件在与sourceVoice.Stop();. 没有功能,lock() {}因为它是可重入的,但它也是无害的。调用 Clear() 时,项目应该已经被删除。

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

两者都不会导致任何“冻结”,因此代码中一定有我们看不到的相关内容。

于 2013-07-09T13:17:41.353 回答
-1

委托只是回调,它们不对线程做任何保证。您可能想查看已经是线程安全的ConcurrentBag 类,因此您可以避免过多担心与集合相关的锁定问题。

于 2013-07-09T13:08:07.547 回答
-2

看起来stop方法的锁定范围内的调用之一可能导致StreamEnd事件触发。您可以通过单步执行stop方法中的代码来测试它是否会跳转到事件中。我会冒险猜测它是sourceVoice.Stop()调用。

于 2013-07-09T13:10:16.040 回答
-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()——它是否创建一个新列表?

于 2013-07-09T13:41:22.040 回答