Возврат словаря в c # в многопоточной среде - PullRequest
6 голосов
/ 24 января 2012

Я объявил словарь словарей:

Dictionary<String, Dictionary<String, String>> values;

У меня есть получатель, чтобы получить словарь по определенному индексу:

public Dictionary<String,String> get(String idx)
{
    lock (_lock)
    {
        return values[moduleName];
    }
}

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

public Dictionary<String,String> get(String idx)
{
    lock (_lock)
    {
        return new Dictionary<string, string>(values[moduleName]);
    }
}

Если я не сделаю, чтобы класс, вызывающий метод получения, получил копию (поэтому, если я удалю этот словарь из моего Dictionary<String, Dictionary<String, String>>, он все еще будет работать)?

Приветствия

Thierry.

Ответы [ 3 ]

6 голосов
/ 24 января 2012

Dictionary<> не является поточно-ориентированным, но ConncurrentDictionary<> является.

Класс, вызывающий метод получения, получает ссылку, что означает, что он все еще будет там, если вы удалите его из values -Dictionary, поскольку GC не очищает его, пока у вас есть ссылка где-то, выпросто не могу получить его с помощью геттера.

По сути это означает, что у вас есть две возможности при использовании Dictionary<>:

  • вернуть копию : Плохоидея, потому что если вы измените конфигурацию, у вас есть две разные конфигурации в вашем приложении "вживую"
  • заблокировать экземпляр : это сделает его поточно-ориентированным, но затем используйте ConcurrentDictionary<> какон делает именно это для вас
4 голосов
/ 24 января 2012

Если вам действительно нужно вернуть сам словарь, то вам нужно будет либо иметь правила для того, как потоки блокируют его (хрупкие, что, если есть случай, который не делает?), Используйте его вспособ только для чтения (словарь является потокобезопасным для чтения только, но обратите внимание, что это предполагает, что частный для класса код также не записывает в него), используйте потокобезопасный словарь (ConcurrentDictionary использует чередующийсяблокировка, my ThreadSafeDictionary использует подходы без блокировок, и существуют различные сценарии, когда один бьет другой), или сделайте копию, как вы предлагаете.

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

2 голосов
/ 24 января 2012

Если вы не вернете копию, вызывающая сторона сможет изменить словарь, но это не проблема безопасности потока.

Существует также проблема безопасности потока, потому что вы не выставляете блокировку для синхронизации записи и чтения. Например, ваш поток записи может добавлять / удалять значение, когда поток чтения работает на том же экземпляре.

Да, вы должны вернуть копию.

...