Этот класс безопасен для потоков? - PullRequest
2 голосов
/ 27 апреля 2009

Является ли этот класс ValueStore потокобезопасным? Нужно ли расширять область блокировки в GetInt (строковый ключ) вокруг возвращаемого значения?

public class ValueStore
{
  private readonly object _locker = new object();
  private readonly Dictionary<string, int> _data = 
    new Dictionary<string, int>();

  public ValueStore(Dictionary<string, int> data)
  {
    _data = data;
  }

  public IEnumerable<int> GetInt(string key)
  {
    IEnumerable<KeyValuePair<string, int>> selected;
    lock(_locker)
    {
      selected = _data.Where(x => x.Key.Equals(key));
    }

    foreach (KeyValuePair<string, int> pair in selected)
    {
      yield return pair.Value;
    }
  }
}

Похоже, что модульный тест в порядке:

[TestFixture]
public class ValueStoreTest
{
  [Test]
  public void test1()
  {
    Dictionary<string, int> data = new Dictionary<string, int>();
    for (int i = 0; i < 100000; i++)
    {
      data.Add(i.ToString(),i);
    }

    ValueStore vs = new ValueStore(data);

    for (int i = 0; i < 900000; i++)
    {
      ThreadPool.QueueUserWorkItem(delegate
      {
        for (int j = 0; j < 100000; j++)
        {
          IEnumerable<int> d = vs.GetInt(j.ToString());
        }
      });
    }
  }
}

Ответы [ 3 ]

6 голосов
/ 27 апреля 2009

Нет, это определенно не потокобезопасно.

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

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

1 голос
/ 27 апреля 2009

Нет, это не так. Если вы начнете читать и записывать объект Dictionary<string, int>, который вы передали в конструктор, у вас возникнет проблема. Ваше объявление класса _data мгновенно перезаписывается присваиванием в конструкторе.

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

Тогда, я думаю, что вы потокобезопасны, но, очевидно, ваш класс только для чтения.

1 голос
/ 27 апреля 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...