我有一个类(简化示例),如:
public class SomeCollection : ICloneable
{
public void Add(Item item) { /* ... */ }
public void Remove(Item item) { /* ... */ }
public Item Get(Key key) { /* ... */ }
/*
...
*/
public object Clone() { /* ... */ }
}
我需要在线程进入Clone()时没有其他线程可以在Add或Remove中输入但可以输入Get。起初我想到了:
public void Add(Item item) { lock(addLock) { /* ... */ } }
public void Remove(Item item) { lock(removeLock) { /* ... */ } }
public object Clone(Item item)
{
lock(addLock)
{
lock(removeLock)
{
/* ... */
}
}
}
这可行(我认为)但有一些缺点: *我不希望两个线程进入Add to block另一个 - 我正在处理更深层次的代码 *我必须承受每次调用Add或Remove
的锁定开销然后我想到了这个
private volatile bool cloning = false; // notice the volatile keyword
public void Add(Item item)
{
int i = 0;
while(cloning)
{
if (i++ > 20)
throw new TimeoutException();
Thread.Sleep(50); // waits 50 milliseconds
}
/* ... */
} // and the same for Remove
public object Clone()
{
cloning = true;
try
{
/* do the cloning */
} finally { cloning = false; }
}
然而这种方法:
我给了ReadWriterLockSlim一眼,但似乎不适合我的情景。
我需要这个,因为克隆方法需要很长时间(可能需要一秒钟 - 集合是巨大的)并且此时的更改将炸毁枚举器(在foreach循环中使用)。是的,我必须使用foreach,因为底层密钥集合不会暴露除IEnumerable以外的任何东西。
你推荐什么?
答案 0 :(得分:1)
你能解释为什么ReaderWriterLockSlim不适合你的场景吗?
当然,您不会将它用于经典用途,但请将Clone方法视为您的编写者,并将添加/删除方法视为您的读者,我认为它适合。
[编辑]另一件事:如果你走这条路,请确保记录你向后使用ReaderWriterLockSlim的原因,以便下一个阅读代码的人(或者你在六个月内)了解正在发生的事情。< / p>