I have a class (simplified example) like :
public class SomeCollection : ICloneable
{
public void Add(Item item) { /* ... */ }
public void Remove(Item item) { /* ... */ }
public Item Get(Key key) { /* ... */ }
/*
...
*/
public object Clone() { /* ... */ }
}
I need that when a thread enters Clone() no other thread can enter in Add or Remove but can enter in Get. At first I thought of :
public void Add(Item item) { lock(addLock) { /* ... */ } }
public void Remove(Item item) { lock(removeLock) { /* ... */ } }
public object Clone(Item item)
{
lock(addLock)
{
lock(removeLock)
{
/* ... */
}
}
}
This works (I think) but has certain disadvantages : * I don't want two threads entering Add to block one another - I am dealing with that deeper in code * I will have to withstand the locking overhead for each call to Add or Remove
Then I thought of this
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; }
}
However this approach :
- Is more complex
- Clone can enter while a thread hasn't finished executing Add or Remove
- Seems unnatural
I have given ReadWriterLockSlim a short glance but doesn't seem to fit in my scenario.
I need this because the Clone method takes long time (may take over a second - the collection is HUGE) and an alteration in this time will blow up the enumerator (used in a foreach loop). Yes, I must use the foreach since the underlying key collection does not expose anything else than an IEnumerable.
What wouly you recommend?