Мой вопрос наверное тут уже 100500 раз перетёрт, но что-то явного обсуждения найти не могу...
Все время писал такой код:
if(Object.ReferenceEquals(m_pointer,null))
{
Interlocked.CompareExchange(ref m_pointer, new TData(), null);
}
Debug.Assert(!Object.ReferenceEquals(m_pointer,null));
return m_pointer;
И пока (на интеле) проблем не было.
Недавно узрел код типа такого:
var tmp=Volatile.Read(ref m_pointer);
if(!Object.ReferenceEquals(tmp,null))
{
Debug.Assert(!Object.ReferenceEquals(m_pointer,null));
return tmp;
}
Interlocked.CompareExchange(ref m_pointer, new TData(), null);
return m_pointer;
Оригинал. К нему есть другие, дополнительные вопросы...
Я так понимаю, в tmp попадает последнее значение m_pointer, которое могло быть сделано где-то снаружи на другом процессоре.
То есть,
грубо говоря, Volatile.Read заставляет все процессоры проверить и сбросить свои кэши в основную память и только потом читает m_pointer.
---
И меня терзают смутные сомнения.
Мой (первый) вариант хуже тем, что могут быть левые создания TData, которые будут отброшены. Эти "промахи" будут только на стадии инициализации программы.
"Левые" создания могут быть и во втором варианте. Но реже. Поскольку здесь, перед сравнением с null, происходит синхронизация.
Но эта синхронизация выполняется каждый раз, на протяжении всего времени функционирования программы. Так?
То есть второй вариант, формально, в круглосуточно работающих программах, хуже?
Или в первом варианте есть какой-то скрытый косяк, из за которого он отработает не так, как ожидается? Но если он есть, то тогда он есть и во втором варианте. Просто реже проявляется...
---
Тут в голову приходят сумбурные мысли о том, что кэши процессора оперируют блоками, а не байтами. И если в блок с m_pointer попадут постоянно модицируемые значения, то Volatile.Read будет постоянно заставлять процессоры сбрасывать данные в общую память...
Спасибо за то, что дочитали до конца
-- Пользователи не приняли программу. Всех пришлось уничтожить. --