Сегодня я столкнулся с каким-то одноэлементным кодом в нашей кодовой базе
У вас есть такой запутанный код по всей вашей кодовой базе? Этот код делает то же самое:
if (_s == null)
_s = new S();
return _s;
и читается в тысячу раз легче.
Я верю этому ?? это просто трюк с компилятором, и что полученный код все еще НЕ атомарный
Вы правы. C # дает следующие гарантии атомарности:
Чтение и запись следующих типов данных являются атомарными: bool, char, byte, sbyte, short, ushort, uint, int, float и reference. Кроме того, чтение и запись перечислимых типов с базовым типом в предыдущем списке также являются атомарными. Чтение и запись других типов, включая long, ulong, double и decimal, а также определяемые пользователем типы, не гарантированно являются атомарными. Помимо библиотечных функций, разработанных для этой цели, нет гарантии атомарного чтения-изменения-записи, например, в случае увеличения или уменьшения.
Нулевой оператор объединения не входит в этот список гарантий.
Чтобы гарантировать атомарность, нам нужно заблокировать этот бит кода:
lock (_sentence) { return _sentence ?? (_sentence = new Sentence()); } } }
Боже мой, нет. Это сразу падает!
Правильно сделать одно из:
- Перестаньте пытаться писать многопоточный код.
- Напишите синглтон, используя один из безопасных документов Джона Скита на своей странице о синглетонах.
- Используйте класс
Lazy<T>
.
- Блокировка объекта, предназначенного для блокировки этой переменной.
- Используйте Interlocked Compare Exchange для выполнения атомарного теста и установки.