Следует ли использовать синхронизацию в свойствах? - PullRequest
1 голос
/ 25 ноября 2010

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

У меня есть многопоточное приложение, которое должно получать / устанавливать свойства в потоках объектов экземпляра.,В настоящее время он реализован без использования синхронизации, и я пока не заметил никаких проблем.Я использую synclock в распространенных статических методах, но я хотел бы правильно реализовать классы своего экземпляра и обеспечить безопасный поток.

Любая обратная связь будет принята с благодарностью.

Ответы [ 2 ]

3 голосов
/ 25 ноября 2010

Хорошее эмпирическое правило заключается в том, что вам нужно заблокировать, если выполняется любое из следующих условий:

  • , если какое-либо поле объекта будет изменено в более чем одном потоке
  • если любые модификации предполагают доступ к более чем одному полю
  • если любое изменяемое поле имеет тип типа Double, Decimal или структурированное значение
  • , если какие-либо модификации включают чтение-изменение-запись (т.е.добавление к полю или установка одного поля со значением из другого)

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

EDIT: Имейте в виду, что блокировка внутри класса редко бывает достаточной - вам нужно убедиться, что все идет не так, как надо на всем протяжении логической операции .

Как указывает @Bevan, если вызывающему коду необходимо получить доступ к объекту более одного раза, клиентский код должен снимать собственную блокировку на объекте на весь период его работы, чтобы обеспечитьt другой поток не получает «промежуточный» доступ и нарушает его логику.

Вы также должны позаботиться о том, чтобы, если что-то требовалось снять несколько блокировок одновременно, этоони всегда принимаются в том же порядке .Если поток 1 имеет блокировку для экземпляра A и пытается заблокировать экземпляр B, а поток 2 имеет блокировку для экземпляра B и пытается получить блокировку для экземпляра A, оба потока застряли и не могут продолжить - у вас есть тупик.

2 голосов
/ 25 ноября 2010

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

Рассмотрим этот второстепенный пример:

var myObject = ...
var myThreadSafeList = ...
if (!myThreadSafeList.Contains(myObject))
{
    myThreadSafeList.Add(myObject);
}

Даже если в myThreadSafeList заблокированы все методы, это не является потокобезопасным, поскольку другой поток может изменять содержимое списка между вызовами Contains() и Add().

В случае этого списка требуется дополнительный метод: AddIfMissing():

var myObject = ...
var myThreadSafeList = ...
myThreadSafeList.AddIfMissing(myObject);

Только перемещая логику в объект, вы можете окружить обе операции замком и сделать его безопасным.

Без дальнейших подробностей, комментировать дальше сложно, но я бы предложил следующее:

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

Для иллюстрации:

public class Person {
    public string FullName { get; private set; }
    public string FamilyName { get; private set; }
    public string KnownAs { get; private set; }

    public void SetNames( string full, string family, string known) {
        lock (padLock) {
            ...
        }
    }
}
...