Синхронизировать коллекцию чтения и записи в .NET - PullRequest
0 голосов
/ 10 сентября 2010

У меня есть объект, который содержит коллекцию предметов. Я хочу иметь возможность добавлять элементы в коллекцию с помощью метода AddItem, а также просматривать все элементы в коллекции. Мой объект должен быть потокобезопасным. Я использую ReaderWriterLockSlim для обеспечения правильной синхронизации. Как мне синхронизировать метод GoThroughAllItems? Должен ли я просто запустить большую блокировку ReadLock на протяжении всей ее продолжительности, которая может быть очень большой, или я должен снять блокировку для каждого элемента, извлеченного из коллекции, и повторно получить блокировку для следующего?

Вот пример кода:

private ReaderWriterLockSlim @lock = new ReaderWriterLockSlim();
private List items = new List();

public void AddItem(Item item)
{
    this.@lock.EnterWriteLock();

    try
    {
        //do something with item and add it to the collection
        this.items.Add(item);
    }
    finally
    {
        this.@lock.ExitWriteLock();
    }
}

public void GoThroughAllItems()
{
    this.@lock.EnterReadLock();

    try
    {
        foreach (Item item in this.Items)
        {
#if option2
            this.@lock.ExitReadLock();
#endif

            //process item, which may take a long time

#if option2
            this.@lock.EnterReadLock();
#endif
        }
    }

#if option2
    catch
#endif
#if option1
    finally
#endif
    {
        this.@lock.ExitReadLock();
    }
}

Ответы [ 2 ]

0 голосов
/ 10 сентября 2010

Я бы просто выбрал ваш первый вариант с областью чтения вокруг foreach, поскольку в блоке чтения разрешено несколько потоков, не важно, что он довольно медленныйС другой стороны, эксклюзивная операция записи довольно быстрая.Так что это должно быть хорошим решением.

0 голосов
/ 10 сентября 2010

Лучший способ - создать копию коллекции, а затем повторить ее.Он имеет значительные накладные расходы памяти (но вскоре будет выпущен).

Псевдокод:

read lock
   foreach oldColl
      populate newColl
exit lock

   foreach newColl
      do things

, и ваш код с блокировками на элемент не будет работать, потому что другой поток может изменить коллекциюи это приведет к ошибке, потому что foreach не позволяет изменять коллекции.

...