我有一个继承自MemoryStream的类,以提供一些缓冲。该类的工作方式完全符合预期,但在读取过程中我偶尔会收到InvalidOperationException,错误消息为
收藏被修改;枚举操作可能无法执行。
我的代码在下面,枚举集合的唯一行似乎是:
m_buffer = m_buffer.Skip(count).ToList();
但是我有这个以及所有其他可以在锁内修改m_buffer对象的操作,所以我对于Write操作如何干扰Read导致该异常感到困惑?
public class MyMemoryStream : MemoryStream
{
private ManualResetEvent m_dataReady = new ManualResetEvent(false);
private List<byte> m_buffer = new List<byte>();
public override void Write(byte[] buffer, int offset, int count)
{
lock (m_buffer)
{
m_buffer.AddRange(buffer.ToList().Skip(offset).Take(count));
}
m_dataReady.Set();
}
public override int Read(byte[] buffer, int offset, int count)
{
if (m_buffer.Count == 0)
{
// Block until the stream has some more data.
m_dataReady.Reset();
m_dataReady.WaitOne();
}
lock (m_buffer)
{
if (m_buffer.Count >= count)
{
// More bytes available than were requested.
Array.Copy(m_buffer.ToArray(), 0, buffer, offset, count);
m_buffer = m_buffer.Skip(count).ToList();
return count;
}
else
{
int length = m_buffer.Count;
Array.Copy(m_buffer.ToArray(), 0, buffer, offset, length);
m_buffer.Clear();
return length;
}
}
}
}
答案 0 :(得分:5)
我不能确切地说你发布的代码到底出了什么问题,但有点奇怪的是你锁定m_buffer,但是替换缓冲区,以便锁定集合并不总是正在读取和修改的集合
最好使用专用的私有只读对象进行锁定:
private readonly object locker = new object();
// ...
lock(locker)
{
// ...
}
答案 1 :(得分:3)
您在那里至少有一个数据竞争:在Read
方法上,如果您在if(m_buffer.Count == 0)
阻止之后和lock
之前被抢占,Count
可以再次为0。您应该检查lock
内的计数,并使用Monitor.Wait
,Monitor.Pulse
和/或Monitor.PulseAll
进行等待/信号协调,如下所示:
// On Write
lock(m_buffer)
{
// ...
Monitor.PulseAll();
}
// On Read
lock(m_buffer)
{
while(m_buffer.Count == 0)
Monitor.Wait(m_buffer);
// ...
您必须保护对m_buffer
的 所有 访问权限,并且在这方面调用m_buffer.Count
并不特别。
答案 2 :(得分:0)
你是否在某个地方的另一个线程中修改了buffer
的内容,我怀疑这可能是枚举错误而不是m_buffer
。