У меня есть класс (упрощенный пример), например:
public class SomeCollection : ICloneable
{
public void Add(Item item) { /* ... */ }
public void Remove(Item item) { /* ... */ }
public Item Get(Key key) { /* ... */ }
/*
...
*/
public object Clone() { /* ... */ }
}
Мне нужно, чтобы при входе потока в Clone() ни один другой поток не мог войти в "Добавить" или "Удалить", но может войти в 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, чтобы блокировать друг друга - я имею дело с тем, что глубже в коде * Мне нужно будет выдерживать блокировку накладных расходов для каждого вызова для добавления или удаления
Тогда я подумал об этом
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 короткий взгляд, но, похоже, не соответствует моему сценарию.
Мне нужно это, потому что метод Clone занимает много времени (может занять более секунды - коллекция HUGE), и изменение в это время взорвет перечислитель (используется в цикле foreach). Да, я должен использовать foreach, поскольку базовая коллекция ключей не раскрывает ничего, кроме IEnumerable.
Рекомендуем ли вам вы?
Не могли бы вы объяснить, почему ReaderWriterLockSlim не подходит для вашего сценария?
Конечно, вы не будете использовать его для его классического использования, но рассмотрите метод Clone как своего автора и методы добавления/удаления в качестве ваших читателей, и я думаю, что он подходит.
[edit] Еще одна вещь: если вы идете по этому маршруту, убедитесь, что вы документируете, почему используете ReaderWriterLockSlim "назад", поэтому следующий человек, который читает код (или вы через полгода), понимает, что происходит.