Потокобезопасные свойства в C # - PullRequest
3 голосов
/ 19 января 2012

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

Ниже я включил несколько примеров того, что я до сих пор пробовал (класс содержится в BindingList, поэтому его свойства вызывают событие PropertyChangingEventHandler).

Метод 1 - Удваивается

private double _Beta;
public double Beta
{
    get
    {
        return _Beta;
    }
}

private readonly BetaLocker = new object();
public void UpdateBeta(double Value)
{
    lock (BetaLocker)
    {
        _Beta = Value;
        NotifyPropertyChanged("Beta");
    }
}

Метод 2 - Инт.

private int _CurrentPosition;
public int CurrentPosition
{
    get
    {
        return _CurrentPosition;
    }
}

public void UpdatePosition(int UpdateQuantity)
{
    Interlocked.Add(ref _CurrentPosition, UpdateQuantity);
    NotifyPropertyChanged("CurrentPosition");
}

1 Ответ

3 голосов
/ 19 января 2012

По сути - является ли текущий способ, которым я создаю свойства, полностью потокобезопасным как для целых, так и для двойных чисел?

Вы должны спросить себя, что значит быть Thread Safe (да, это ссылка на Википедию и она затемнена ^ _ ^):

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

Итак, теперь вам нужно определить, гарантирует ли ваш код безопасное выполнение, если выполняется несколькими потоками: быстрый ответ заключается в том, что оба примера кода являются потоковымибезопасный! Однако (и это большой), вы также должны рассмотреть вопрос об использовании объекта и определить, является ли он также потокобезопасным ... вот пример:

if(instance.Beta==10.0)
{
   instance.UpdateBeta(instance.Beta*10.0);
}

// what's instance.Beta now?

В этом случае у вас нет абсолютно никаких гарантий, что Beta будет 100.0, потому что бета-версия могла измениться после того, как вы проверили ее.Представьте себе такую ​​ситуацию:

Thread 2: UpdateBeta(10.0)
Thread 1: if(Beta == 10.00)
Thread 2: UpdateBeta(20.0)
Thread 1: UpdateBeta(Beta*10.0)
// Beta is now 200.0!!! 

Быстрый и грязный способ исправить это - использовать блокировку с двойной проверкой:

if(instance.Beta==10.0)
{
    lock(instance)
    {
        if(instance.Beta==10.0)
        {
            instance.UpdateBeta(instance.Beta*10.0);
        }
    }
}

То же самое верно для CurrentPosition.

...