2009-04-27 3 views
2

Является ли этот класс 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()); 
     } 
     }); 
    } 
    } 
} 
+0

У вас более серьезные проблемы, чем безопасность потоков. Вы неправильно используете словарь. Вы используете его, как список. - Кажется, вы думаете, что у вас может быть несколько значений, назначенных ключу. Вы не можете. Таким образом, выход не нужен. - Вы перечисляете все значения в словаре, а не просто используете методы contains/get. –

ответ

6

Нет, это определенно не поточно-.

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

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

1

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

+2

Заявление в замке * * выполняется в замке. Просто этот оператор возвращает итератор отложенного выполнения. * Lambda expression * не выполняется в блокировке, если это то, что вы хотели сказать. –

1

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

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

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

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