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