2017-02-01 4 views
0

Должен ли я иметь какой-либо механизм безопасности потока в следующих простых сборщиках и сеттерах для Словаря?Вопрос безопасности в этом случае?

При необходимости, пожалуйста, примеры как для замка, так и для ConcurrentDictionary.

public virtual void Add(IFoo foo) 
    { 
     dictionary.Add(foo.name, foo); 
    } 

    public virtual IFoo Get(string name) 
    { 
     if (!dictionary.TryGetValue(name, out IFoo foo)) return null; 
     return foo; 
    } 

    public virtual bool Has(string name) 
    { 
     return dictionary.TryGetValue(name, out IFoo foo); 
    } 

    public virtual IFoo Remove(string name) 
    { 
     if (dictionary.TryGetValue(name, out IFoo foo)) 
     { 
      dictionary.Remove(name); 
     } 
     return foo; 
    } 

    protected readonly IDictionary<string, IFoo> dictionary = new Dictionary<string, IFoo>(); 
+3

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

+0

мой первый вопрос: действительно ли нужно иметь безопасность потока в приведенном выше случае? пожалуйста, посоветуйте мне некоторые рекомендации, тогда я отредактирую – user2727195

+1

как этот код используется? Покажите нам фактический многопоточный код, который вы использовали. – fofik

ответ

1

В соответствии с запросом, используйте поточную версию с блокировкой. Метод «Добавить» может вызывать либо GetOrAdd, либо AddOrUpdate, в зависимости от того, хотите ли вы выиграть «первый выигрыш» или «последний выигрывает» в случае разногласий.

А вот версия с ConcurrentDictionary:

public virtual void Add(IFoo foo) 
{ 
    AddOrUpdate(foo); // If you want "last one wins" 
    //GetOrAdd(foo);  // If you want "first one wins" 
} 

private virtual IFoo GetOrAdd(IFoo foo) 
{ 
    return concurrentDictionary.GetOrAdd(foo.name, foo); 
} 
public virtual void AddOrUpdate(IFoo foo) 
{ 
    concurrentDictionary[foo.name] = foo; 
} 

public virtual IFoo Get(string name) 
{ 
    IFoo result; 
    concurrentDictionary.TryGetValue(name, out result); 
    return result; // will be null if TryGetValue returned false 
} 

public virtual bool Has(string name) 
{ 
    return concurrentDictionary.ContainsKey(name); 
    // But there's no guarantee it's still there when this method returns 
} 

public virtual IFoo Remove(string name) 
{ 
    IFoo result; 
    concurrentDictionary.TryRemove(name, out result); 
    return result; 
} 

private readonly ConcurrentDictionary<string, IFoo> concurrentDictionary = new ConcurrentDictionary<string, IFoo>(); 
+0

Спасибо Джо, есть ли больше объяснений для первого выигрыша, а последний выигрывает. – user2727195

+0

«first one wins» означает, что если два потока одновременно вызывают метод Add, то первый добавит элемент в словарь, а второй - нет. «last one wins» означает, что в этой ситуации первый поток добавит свой элемент в словарь, а второй перезапишет его. Прочитайте документацию MSDN для ConcurrentDictionary.GetOrAdd, если она еще не понятна. – Joe

+0

'Но нет никакой гарантии, что он все еще там, когда этот метод возвращается', так что вы рекомендуете покрывать этот угол, ставить блокировку в каждую функцию? – user2727195

0

Если ваш словарь будет доступен из разных потоков, то вы должны прочитать следующее о Словаре:

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

Я предлагаю использовать ConcurrentDictionary<TKey, TValue> как поточно-коллекции он обеспечивает методы, которые являются атомные и поточно-:

Все эти операции являются атомарными и потокобезопасны в отношении всех других операций по класс ConcurrentDictionary. Единственными исключениями являются методы, которые принимают делегат, то есть AddOrUpdate и GetOrAdd.

проверить эту ссылку: https://msdn.microsoft.com/en-us/library/dd287191(v=vs.110).aspx

вместо того, чтобы использовать свой собственный код блокировки, однако вы можете использовать lock заявление для осуществления синхронизации потоков в случае, если вы хотите использовать Dictionary, проверьте эту ссылку: https://msdn.microsoft.com/en-us/library/c5kehkcz.aspx

+0

«Чтобы обеспечить доступ к коллекции несколькими потоками для чтения и записи, вы должны реализовать свою собственную синхронизацию». это применимо и к ConcurrentDictionary? Представьте, что если выше словарь был ConcurrentDictionary, будет использовать lock (this) {} в каждой функции add, get, remove? – user2727195

+0

Блокировка может использоваться с Словарем, но в случае ConcurrentDictionary в большинстве методов не требуется, единственными исключениями являются методы, которые принимают делегат. –

+0

oh ваше редактирование вызвало беспокойство, у меня был другой вопрос, который использовал GetOrAdd, и я никогда не запирал его, не глядя на него, чтобы убедиться, что он потокобезопасен? http://stackoverflow.com/questions/41865146/concurrency-with-reading-but-locking-with-mutating проверить ответ Скотта на Code # 2 и # 3. – user2727195

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