Блокировка нескольких методов, только если поток находится в определенном методе

2

У меня есть класс (упрощенный пример), например:

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.

Рекомендуем ли вам вы?

Теги:
multithreading
locking

1 ответ

1
Лучший ответ

Не могли бы вы объяснить, почему ReaderWriterLockSlim не подходит для вашего сценария?

Конечно, вы не будете использовать его для его классического использования, но рассмотрите метод Clone как своего автора и методы добавления/удаления в качестве ваших читателей, и я думаю, что он подходит.

[edit] Еще одна вещь: если вы идете по этому маршруту, убедитесь, что вы документируете, почему используете ReaderWriterLockSlim "назад", поэтому следующий человек, который читает код (или вы через полгода), понимает, что происходит.

  • 0
    Да, я считал одно и то же: клон - писатель, Add and Remove в качестве читателей. Во-первых, имена операций инвертированы. Я имею в виду, что «Добавить» и «Удалить» действительно пишут, а Клон читает. Но это больше похоже на не проблему. Во-вторых, я не совсем понимаю наверняка, будет ли он блокировать операцию чтения во время чтения и блокировать операцию записи во время чтения. Но опять же, я должен снова прочитать документацию. Я, конечно, надеюсь, что вы правы в этом. Это ответило бы на мой вопрос отлично. : D TX!
  • 0
    Я прочитал документацию, и у нее есть хорошая таблица, которая ясно объясняет возможные взаимодействия между потоком и блокировкой. Спасибо. Это, кажется, ответ для меня.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню