2009-03-30 2 views
1

Я использую шаблон фабрики для создания настраиваемого объекта, который загружается из кеша, если это возможно. На пользовательский объект нет статических элементов или функций.Безопасность потоков в общих экземплярах (C#)

Предполагая, что 2 потока вызывают фабрику и возвращают ссылки на один и тот же объект из кеша. (Т.е. Нет нового оператора, в ссылке, чтобы ответить ниже, возвращаемый объект из коллекции)

Если я хочу изменить закрытый член экземпляра внутри класса:

а) Shoulb я запирать его первым? b) Будет ли отражение отражено в обоих потоках?

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

Должен ли я иметь что-то фундаментальное здесь? Почему я чувствую, что у меня есть?

===============

После первых нескольких ответов я подтвердил то, что я думал, спасибо.

Я предполагаю, что я действительно хочу знать, если объекты в значительной степени доступны только для чтения, т. Е. После их создания у них есть только один член экземпляра, который может меняться, мне нужно делать какие-либо блокировки при чтении свойств, которые не влияет этот один измененный член экземпляра? не

Опять я полагаю, нет, но я должен прийти ценить второе мнение коллективного StackOverflow мозги доверяют :)

ответ

2

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

public SomeClass SomeProperty 
{ 
    get 
    { 
     lock (someLock) 
     { 
      return someField; 
     } 
    } 

    set 
    { 
     lock (someLock) 
     { 
      someField = value; 
     } 
    } 
} 

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

Следует также отметить, что поддержка Hashtable и Dictionary поддерживает одновременное считывание без необходимости каких-либо блокировок.

0

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

1

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

1

Это должен быть тот же объект, и ответ на ваши вопросы ДА, ДА.

Как вы проверяете наличие двух экземпляров?

1

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

Однако, возможно, потребуется некоторое время, чтобы рассмотреть, как обращаться с замками и потоками.

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

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

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

0

У вас есть для просмотра результатов смены частного участника? Или все в порядке с вами, если оба потока получают объект, но когда один поток изменяет частный член, другой поток не видит этого изменения?

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

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

Будьте осторожны с идеей «клона». Если у вас есть график объектов, и вы делаете только мелкий клон, вы получите ссылки, которые по-прежнему используются для потоков, заставляя вас снова синхронизировать. Идея создания одной копии в потоке имеет смысл, если объект является очень простым объектом без большого количества ссылок на другие объекты.

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