Threading: блокировка общего словаря - PullRequest
1 голос
/ 08 апреля 2009

У меня есть универсальный словарь в многопоточном приложении; для реализации блокировки я создал свойство.

static object myLock=new object();
Dictionary<key,SomeRef> dict=new Dictionary<key,SomeRef>();

public Dictionary<key,SomeRef> MyDict{
      get{
        lock(myLock){
        return dict;
        }
     }
 }

Теперь, если я напишу КОД № 1

 MyDict.TryGetValue

или КОД № 2

var result=MyDict.Values;
foreach(var item in result){
//read value into some other variable
}

так что пока я выполняю код 1 или 2 и в то же время, если какой-то другой поток пытается выполнить какую-либо операцию записи в словаре, например ..clear dict или добавить новый элемент. тогда будет ли это решение поточно-ориентированным (используя свойство). если нет .. то есть ли другие способы сделать это.

Когда я говорю «операция записи», можно взять ссылку на dict с помощью свойства chek key exoist или нет, если не создать ключ и присвоить значение. (таким образом я не использую сеттер в свойстве)

Ответы [ 4 ]

4 голосов
/ 08 апреля 2009

Нет, это не будет потокобезопасным.

Блокировка будет блокироваться только при получении ссылки на ваш внутренний (dict) экземпляр словаря. Он не блокируется, когда пользователь пытается добавить в словарь или прочитать из словаря.

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


Это будет выглядеть примерно так:

public bool TryGetValue(key thekey, out SomeRef result)
{
    lock(myLock) { return this.dict.TryGetValue(thekey, out result); }
}
public void Add(key thekey, SomeRef value)
{
    lock(myLock) { this.dict.Add(thekey, value) }
}
// etc for each method you need to implement...

Идея в том, что ваши клиенты используют ваш класс напрямую, а ваш класс обрабатывает синхронизацию. Если вы ожидаете, что они будут перебирать значения (например, оператор foreach), вы можете решить, следует ли скопировать значения в список и вернуть его или предоставить перечислитель напрямую (IEnumerator<SomeRef> GetValues()) и т. Д.

3 голосов
/ 08 апреля 2009

Нет, это не будет безопасно, так как единственный код, который locked - это код для поиска. Что вам нужно сделать, это

lock(MyDict)
{
   if(MyDict.TryGetValue()...
}

и

lock(MyDict)
{
    foreach(var item in MyDict.Values) ...
}

Основная идея заключается в том, чтобы заключить ваш рабочий код в блок lock ().

2 голосов
/ 08 апреля 2009

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

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

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

Потокобезопасный словарь в .NET с ReaderWriterLockSlim Этот метод использует ReaderWriterLockSlim и детерминированный финализатор для удержания и снятия блокировок.

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