1

У меня есть общий объект между потоками, который используется для хранения информации состояния файла. Объект, который содержит информацию этот класс:Резервное перечисление разделяемой памяти, которое может быть обновлено или удалено

/// <summary> 
/// A synchronized dictionary class. 
/// Uses ReaderWriterLockSlim to handle locking. The dictionary does not allow recursion by enumeration. It is purly used for quick read access. 
/// </summary> 
/// <typeparam name="T">Type that is going to be kept.</typeparam> 
public sealed class SynchronizedDictionary<U,T> : IEnumerable<T> 
{ 
    private System.Threading.ReaderWriterLockSlim _lock = new System.Threading.ReaderWriterLockSlim(); 
    private Dictionary<U, T> _collection = null; 

    public SynchronizedDictionary() 
    { 
     _collection = new Dictionary<U, T>(); 
    } 

    /// <summary> 
    /// if getting: 
    /// Enters read lock. 
    /// Tries to get the value. 
    /// 
    /// if setting: 
    /// Enters write lock. 
    /// Tries to set value. 
    /// </summary> 
    /// <param name="key">The key to fetch the value with.</param> 
    /// <returns>Object of T</returns> 
    public T this[U key] 
    { 
     get 
     { 
      _lock.EnterReadLock(); 
      try 
      { 
       return _collection[key]; 
      } 
      finally 
      { 
       _lock.ExitReadLock(); 
      } 
     } 

     set 
     { 
      Add(key, value); 
     } 

    } 

    /// <summary> 
    /// Enters write lock. 
    /// Removes key from collection 
    /// </summary> 
    /// <param name="key">Key to remove.</param> 
    public void Remove(U key) 
    { 
     _lock.EnterWriteLock(); 
     try 
     { 
      _collection.Remove(key); 
     } 
     finally 
     { 
      _lock.ExitWriteLock(); 
     } 
    } 

    /// <summary> 
    /// Enters write lock. 
    /// Adds value to the collection if key does not exists. 
    /// </summary> 
    /// <param name="key">Key to add.</param> 
    /// <param name="value">Value to add.</param> 
    private void Add(U key, T value) 
    { 
     _lock.EnterWriteLock(); 
     if (!_collection.ContainsKey(key)) 
     { 
      try 
      { 
       _collection[key] = value; 
      } 
      finally 
      { 
       _lock.ExitWriteLock(); 
      } 
     } 

    } 

    /// <summary> 
    /// Collection does not support iteration. 
    /// </summary> 
    /// <returns>Throw NotSupportedException</returns> 
    public IEnumerator<T> GetEnumerator() 
    { 
     throw new NotSupportedException(); 
    } 

    /// <summary> 
    /// Collection does not support iteration. 
    /// </summary> 
    /// <returns>Throw NotSupportedException</returns> 
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
    { 
     throw new NotSupportedException(); 
    } 

}

Я называю этот словарь, как это: SynchronizedDictionary _cache = новый SynchronizedDictionary();

Другие темы могут быть созданы и использованы как нить: _cache ["key"];

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

  1. Создание Enumerator вроде этого: http://www.codeproject.com/Articles/56575/Thread-safe-enumeration-in-C (но с использованием ReaderWriterLockSlim)
  2. Expose объект блокировки, как SyncRoot делает (но с ReaderWriterLockSlim), поэтому абонент звонит методы ввода и выхода.
  3. Вместо этого используйте базу данных (SQLite fx), содержащую информацию.

Проблема с номером 1) является:

  1. он использует застройщик в режим входа для чтения. Что делать, если GetEnumerator() вызывает вызов вручную, не используя foreach? И забудьте отправить .
  2. Я не знаю, является ли это хорошим стилем кодирования. Хотя мне нравится код .
  3. Если вызывающий абонент использует foreach, я не знаю, что вызывающий может сделать между экземпляром перечислителя и вызовом для удаления. Если я понял документацию, которую я прочитал правильно, это может в конечном итоге блокировать писателя, пока есть один читатель, который делает некоторые тяжелые работы.

Проблема с номером 2) является:

  1. Я не люблю подвергать это. Я знаю, что .NET API делает это, но ему не нравится.
  2. Это до вызывающего абонента для входа и выхода правильно

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

Возможно, это только я изобрел проблему?

Я знаю о ConcurrentDictionary, но я не хочу использовать это. Я использую этот проект в качестве игровой площадки.Игра с резьбой и отражением.

EDIT

Я спросил, что это такое, что я читать и писать. И я расскажу об этом в этом редактировании. Я читаю и пишу этот класс:

public class AssemblyInformation 
{ 
    public string FilePath { get; private set; } 
    public string Name { get; private set; } 

    public AssemblyInformation(string filePath, string name) 
    { 
     FilePath = filePath; 
     Name = name; 
    } 
} 

Я делаю много чтений и почти не пишет во время выполнения. Может быть, я сделаю 2000 и 1 напишу. Не может быть и много объектов, может быть 200.

+0

Кажется, хороший вопрос, но слишком долго читать –

+0

Извините, но я не знаю способа, говоря это короче. – mslot

+0

У меня проблемы. Если вы каким-то образом не выбрали гениальный ключ для словаря. Это просто не проблема, если вы используете полный путь к DLL в качестве ключа. –

ответ

2

Я буду рассматривать ваши вопросы как запрос обратной связи, который поможет вам учиться. Позвольте мне рассмотреть три решения, которые вы уже определили:

  1. Да, поэтому такой дизайн никогда не должен отображаться как API для сторонних разработчиков (или даже других разработчиков). Трудно правильно использовать. В этой статье кодекса есть несколько неприятных советов.
  2. Гораздо лучше, потому что эта модель будет явно связана с блокировкой, а не подразумевается. Однако это, по моему мнению, нарушает разделение проблем.
  3. Не уверен, что вы имеете в виду здесь. У вас может быть метод Snapshot() для вашего словаря, который делает копию только для чтения, которую можно безопасно передавать и читать. Это другое компромиссное решение, чем решение 1.

Существует совершенно другое решение: используйте неизменный словарь. Такой словарь можно было бы передавать, читать и перечислять безопасно даже при одновременном доступе к записи. Такие словари/карты обычно реализуются с использованием деревьев.

Подробнее я расскажу о ключевой момент: вам нужно подумать о параллельной системе в целом. Вы не можете сделать приложение правильным, сделав все компоненты потокобезопасными (в вашем случае словарь). Вам нужно определить, что вы используете словарь для.

Вы говорите:

Причина, почему я хочу итерацию по коллекции во время выполнения , что я хочу, чтобы найти значения, которые соответствуют определенным критериям.

У вас есть параллельные записи, происходящие с данными, и вы хотите получить последовательный моментальный снимок из словаря (возможно, для снятия некоторого отчета о проделанной работе в пользовательском интерфейсе?). Теперь, когда мы знаем эту цель, мы можем разработать решение:

Вы можете добавить метод Clone к вашему словарю, который клонирует все данные во время чтения-блокировки. Это даст вызывающему абоненту новый объект, который он может перечислить самостоятельно. Это будет чистый и безопасно отображаемый API.

+0

Да, мне нужна обратная связь :) Я обновил свой 3 вопрос. Но я вижу, что вы это поняли. Меня больше интересует слух о вашем «другом решении». Вы говорите о каком-то «ReadOnlyDictionary»? – mslot

+0

Я добавил больше мысли. Для чего вы используете словарь? Что вы читаете и пишете? – usr

+0

Мне нравится способ мышления. Я редактировал свой вопрос и добавлял некоторую информацию о том, что я читаю и пишу. Это не так много, и, возможно, где-то в моем сознании я знаю, что я мог бы легко сделать клон и прочитать это. Возможно, это просто лучшее решение, потому что это даст мне действительный след списка в текущее время. Но я думаю, что это потребление, хотя я не работаю над множеством объектов. – mslot

1

Вместо реализации IEnumerable непосредственно я хотел бы добавить Values свойство (как Dictionary.Values):

public IEnumerable<T> Values { 
    get { 
    _lock.EnterReadLock(); 
    try { 
     foreach (T v in _collection.Values) { 
     yield return v; 
     } 
    } finally { 
     _lock.ExitReadLock(); 
    } 
    } 
} 
+0

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

+1

Добро пожаловать. Конечно, с помощью той же методики вы можете вернуть перечисление пар ключ-значение. – MiMo

Смежные вопросы