2010-11-25 2 views
1

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

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

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

+0

Вам нужно было бы заблокировать («SyncLock»), если бы вы использовали метод, например, `SetX()` вместо set `X`? Без полного контекста трудно сказать. Кроме того, не зная более обширного контекста, невозможно определить, разрешают ли отдельные блокировки/адресуют * реальные * проблемы. «Резьба - это легко. Параллелизм - это сложно». – 2010-11-25 00:35:59

+0

Возможно, см .: http://stackoverflow.com/questions/505515/c-thread-safety-with-get-set – 2010-11-25 00:36:32

+0

@pst. Я прочитал несколько вещей о замене свойств методами и, похоже, не получил четкого ответа на это тоже. Насколько я понимаю, свойство по существу является простым методом. Поскольку я реализовал приложение, используя дизайн свойства/поля, я хотел бы попытаться сохранить его таким образом. Я предполагаю, что речь идет скорее о хорошей практике проектирования и безопасности потоков. Спасибо за ссылку, я думал, что провел тщательный поиск, но не видел этого! – Netpuppy 2010-11-25 00:43:24

ответ

3

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

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

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

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

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

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

2

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

Рассмотрим этот незначительный пример:

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

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

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

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

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

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

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

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

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) { 
      ... 
     } 
    } 
} 
Смежные вопросы