В книге Энтони Уильямса "Параллельное программирование на C++ в действии" рекомендуется заменять использование упомянутого в заголовке паттерна использованием std::call_once
. Немного погуглив, обнаружил, что в других языках, например, Java и C# подобная проблема решается объявление переменной как volatile
для предотвращение оптимизаций компилятором. Является ли использование volatile
решением и в C++ ? Или же здесь она работает как-то иначе?
нет, не является. Дело в том, что даже в этом случае можно сделать "обход". Детально расписано на хабре.
Суть в том, что мы думаем, что в коде, одна строка атомарна, а это далеко не так.
template<typename T>
T& single()
{
static T* pt;
if (pt == 0) // первая проверка, вне мьютекса
{
StaticLock lock;
if (pt == 0) // вторая проверка, под мьютексом
pt = new T; // вот здесь на самом деле две строки.
}
return *pt;
}
создание объекта это обычно две операции - собственно выделение память и вызов конструктора. И в этом случае может так оказаться, что память уже выделили, а по адресу ещё не создали объект. И самая первая проверка теперь отработает по другому.
Может вы уже видели эту статью, если "гуглили" :), но там указано:
Если вы укажете перед переменной volatile, то оптимизиации не будет.
Хотя, использовать volotile
для доступа к переменным из разных потоков -
не корректно , т.к. предназначено оно для для работы с memory mapped
Подробнее: Описание volatile c++
P.S. Если я правильно понял вопрос.
Мейерс пишет, что volatile
применяется для памяти, чтения и записи которой не должны удаляться при оптимизации, и что надо четко отличать volatile
и std::atomic
, который применяется для обращения нескольких потоков к данным без использования мьютексов.
Если это не в тему - извините :(
В случае MSVC, под volatile
потокобезопасность подразумевается (за исключением архитектуры ARM). Конкретно, MSVC генерирует дополнительный исполняемый код для обеспечения особого порядка доступа к переменной из разных потоков. Такое поведение задается ключом компилятора /volatile:ms
.
Напротив ключ /volatile:iso
задает поведение по стандарту, то есть квалификатор volatile
отключает оптимизации и к потокобезопасности явного отношения не имеет.
При этом по умолчанию, в MSVC подразумевается /volatile:ms
, то есть поведение MSVC в отношении volatile
не является стандартным по умолчанию!
Оборудование для ресторана: новинки профессиональной кухонной техники
Частный дом престарелых в Киеве: комфорт, забота и профессиональный уход
Какая -то фигняОшибок при компиляции не выдает, но не работает