Страница: 1 |
Вопрос: Блокировка с двойной проверкой | Добавлено: 17.09.10 11:29 |
Автор вопроса: ![]() |
Есть классическая древовидная структура, с «ленивой инициализацией». В однопоточной модели, проблем не. Но как быть с многопоточной моделью. Привожу 3 варианта решения проблемы: свойства Items1, Items2, Items3
Items1 - проблем нет, но постоянные блокировки. Items2 - есть проблемы и то, что это плохой вариант, я знаю. Items3 – интуитивно, проблем нету и блокировка только при первом обращении. Но это на интуитивном уровне. Хотелось бы услышать мнения гуру по этому варианту. Public Class Folders Inherits List(Of Folder) Friend Owner As Folder Public Sub New(ByVal owner As Folder) Me.Owner = owner End Sub End Class Public Class Folder Private _Items As Folders Private SyncRoot As Object = New Object ' 100% гарантия синхронизации. Но постоянные блокировки, даже при чтении свойства. Public ReadOnly Property Items1 As Folders Get SyncLock(Me.SyncRoot) If Me._Items Is Nothing Then Me._Items = New Folders(Me) End If End SyncLock Return Me._Items End Get End Property ' Блокировка только при первом обращении. Но большая вероятность не атомарного выполнения конструктора. ' И как следствие, другой поток может получить ссылку на _Items, которое уже не Nothing, но еще не полностью инициализировано. Public ReadOnly Property Items2 As Folders Get If Me._Items Is Nothing Then SyncLock(Me.SyncRoot) If Me._Items Is Nothing Then Me._Items = New Folders(Me) End If End SyncLock End If Return Me._Items End Get End Property ' Тоже что и во втором варианте, тока инициализация _Items с помощью класса System.Threading.Interlocked Public ReadOnly Property Items3 As Folders Get If Me._Items Is Nothing Then SyncLock(Me.SyncRoot) If Me._Items Is Nothing Then Dim instance As New Folders(Me) System.Threading.Interlocked.Exchange(Of Folders)(Me._Items, instance) End If End SyncLock End If Return Me._Items End Get End Property End Class |
Ответы | Всего ответов: 14 |
Номер ответа: 1 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() Вопросов: 1 Ответов: 5 |
Профиль | Цитата | #1 | Добавлено: 17.09.10 11:32 |
|
Номер ответа: 2 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Разработчик Вопросов: 130 Ответов: 6602 |
Профиль | Цитата | #2 | Добавлено: 17.09.10 15:39 |
# ' Блокировка только при первом обращении. Но большая вероятность не атомарного выполнения конструктора.
# ' И как следствие, другой поток может получить ссылку на _Items, которое уже не Nothing, но еще не полностью инициализировано. Конструктор не атомарен, но присваивание атомарно. Ссылка на объект будет полчена когда он уже полностью проинициализирован (т.е. когда конструктор завершится), поэтому проблем не будет. ' Тоже что и во втором варианте, тока инициализация _Items с помощью класса System.Threading.Interlocked
Это лишнее. Неатомарно может быть присваивание Int64 (при сборке под x64 - уже атомарно). Тогда нужно делать обмен через Interlocked.Exchange. Посмотри еще на Lazy<T>. Он появился в 4.0. |
Номер ответа: 3 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() Вопросов: 1 Ответов: 5 |
Профиль | Цитата | #3 | Добавлено: 17.09.10 16:00 |
Если присваивание атомарно, для ссылочных типов, тогда зачем нужна перегрузка метода Interlocked.Exchange с параметрами ссылочного типа?
Например с свойством Items2 работают два потока A и B. Например поток В добрался до свойства первым и начал инициализацию _Items. Но не завершил ее до конца. Начал работу поток А он видит что _Items уже не Nothing и сразу попадает в строку Return Me._Items. Но ведь объект еще не готов. Во всяком случаи, об этом написано тут. http://ru.wikipedia.org/wiki/Double_checked_locking. Если рассматривать свойство Items3 и то, что операция присваивания ссылки атомарна, то Interlocked.Exchange действительно лишнее. Но это в теории. |
Номер ответа: 4 Автор ответа: ![]() ![]() ![]() ![]() ![]() Вопросов: 58 Ответов: 4255 ![]() |
Профиль | Цитата | #4 | Добавлено: 17.09.10 16:45 |
MS рекомендует юзать модификатор volatile
Вот их рекомендации по реализации паттерна Singleton http://msdn.microsoft.com/en-us/library/ms998558.aspx |
Номер ответа: 5 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() Вопросов: 1 Ответов: 5 |
Профиль | Цитата | #5 | Добавлено: 17.09.10 16:53 |
паттерн Singleton применим к "ленивой инициализации" одного экземпляра, мне же надо реализовать для множества экземпляров. |
Номер ответа: 6 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() Вопросов: 1 Ответов: 5 |
Профиль | Цитата | #6 | Добавлено: 17.09.10 16:55 |
в принципе, теоретически, обращение к свойству Items3 решает все проблемы. Вопрос был в следующем, действительно ли он решает все проблемы? |
Номер ответа: 7 Автор ответа: ![]() ![]() ![]() ![]() ![]() Вопросов: 58 Ответов: 4255 ![]() |
Профиль | Цитата | #7 | Добавлено: 17.09.10 17:08 |
Вопрос был в следующем, действительно ли он решает все проблемы?
я думаю да, проблем быть не должно.. |
Номер ответа: 8 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() Вопросов: 1 Ответов: 5 |
Профиль | Цитата | #8 | Добавлено: 17.09.10 17:24 |
Конструктор не атомарен, но присваивание атомарно. Ссылка на объект будет полчена когда он уже полностью проинициализирован (т.е. когда конструктор завершится), поэтому проблем не будет. Как утверждал Artyom присваивание атомарно, но действительно ли это так (разная архитектура, система)? Тобишь операция Me._Items = instance выполниться атомарно. Или все же лучше использовать Interlocked.Exchange?
|
Номер ответа: 9 Автор ответа: ![]() ![]() ![]() ![]() ![]() Вопросов: 58 Ответов: 4255 ![]() |
Профиль | Цитата | #9 | Добавлено: 17.09.10 17:43 |
Или все же лучше использовать Interlocked.Exchange?
Можешь использовать,страшного ничего не будет.. но Artyom прав.. это лишнее, поскольку операция присвоения ссылки атомарная.. |
Номер ответа: 10 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Разработчик Вопросов: 130 Ответов: 6602 |
Профиль | Цитата | #10 | Добавлено: 18.09.10 04:49 |
Рассово верное решение на Lazy<T>
Кстати я ошибался, он на самом деле ещ ев 3.5 появился.
|
Номер ответа: 11 Автор ответа: ![]() ![]() ![]() ![]() Вопросов: 26 Ответов: 295 |
Профиль | Цитата | #11 | Добавлено: 18.09.10 14:48 |
Кстати я ошибался, он на самом деле ещ ев 3.5 появился
Нет, Artyom, нет его в 3,5. |
Номер ответа: 12 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Разработчик Вопросов: 130 Ответов: 6602 |
Профиль | Цитата | #12 | Добавлено: 18.09.10 19:43 |
Есть, если верить MSDN, которой я имею основания верить |
Номер ответа: 13 Автор ответа: ![]() ![]() ![]() ![]() ![]() Вопросов: 58 Ответов: 4255 ![]() |
Профиль | Цитата | #13 | Добавлено: 18.09.10 20:41 |
Значит выкинь свою MSDN, потому что она тебе нагло врет.. |
Номер ответа: 14 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Разработчик Вопросов: 130 Ответов: 6602 |
Профиль | Цитата | #14 | Добавлено: 19.09.10 01:07 |
Виноват, не в тот раздел посмотрел.
В 3.5 этого класса нет, только в 4.0, впрочем это один из тысячи поводов переходить на 4.0 ![]() |
Страница: 1 |
|