Если вы хотите реализовать свойство таким образом, чтобы DoneCounter = DoneCounter + 1
гарантированно не зависело от условий гонки, этого нельзя сделать при реализации свойства.Эта операция не является атомарной, на самом деле это три отдельных шага:
- Получить значение
DoneCounter
. - Добавить 1
- Сохранить результат в
DoneCounter
.
Вы должны остерегаться возможности того, что переключение контекста может произойти между любыми из этих шагов.Блокировка внутри метода получения или установки не поможет, потому что область действия блокировки полностью существует в пределах одного из шагов (1 или 3).Если вы хотите, чтобы все три шага происходили вместе, не прерываясь, то ваша синхронизация должна охватывать все три шага.Это означает, что это должно происходить в контексте, который содержит все три из них.Возможно, в конечном итоге это будет код, который не принадлежит ни к какому классу, содержащему свойство DoneCounter
.
Ответственность за безопасность потоков лежит на человеке, использующем ваш объект.В общем, ни один класс, имеющий поля или свойства для чтения / записи, не может быть таким образом «поточно-ориентированным».Однако, если вы можете изменить интерфейс класса так, чтобы установщики не были нужны, то можно сделать его более потокобезопасным.Например, если вы знаете, что DoneCounter только увеличивает и уменьшает значение, вы можете реализовать его следующим образом:
private int _doneCounter;
public int DoneCounter { get { return _doneCounter; } }
public int IncrementDoneCounter() { return Interlocked.Increment(ref _doneCounter); }
public int DecrementDoneCounter() { return Interlocked.Decrement(ref _doneCounter); }