Да, это безопасно!
Если Acquire-load возвращает null (т. Е. Синглтон еще не инициализирован), вы получаете мьютекс. Внутри мьютекса перезагрузка может быть ослаблена, поскольку модификации m_instance
в любом случае защищены мьютексом, т. Е. Если какой-то другой поток уже инициализировал синглтон, то мьютекс-релиз этого потока должен произойти до того, как наш мьютекс-захват операции, поэтому гарантируется, что мы увидим обновленный m_instance
.
Если Acquire-load (1) «видит» значение, записанное хранилищем Release (2), две операции синхронизируются с друг с другом, тем самым устанавливая связь «происходит раньше», так что вы можете безопасно получить доступ к объекту, на который указывает tmp.
Обновление
Release-store также защищен мьютексом, и он не возможно, что часть инициализации tmp переупорядочена с хранилищем. В общем, не следует спорить о возможных переупорядочениях. Стандарт не говорит ничего о том, можно ли / как можно переупорядочить операции. Вместо этого он определяет отношение (между потоками) -случалось-до. Любые переупорядочения, которые может выполнить компилятор, являются просто результатом применения правил отношений «происходит до».
Если приобретение-загрузка (1) загружает значение, записанное хранилищем выпуска (2), две операции синхронизируются друг с другом, тем самым устанавливая связь «происходит до», т. е. (2) происходит до (3). Но поскольку (1) упорядочивается до (2), а отношение «произошло до» транзитивно, необходимо гарантировать, что (1) произойдет до (3). Таким образом, переупорядочить (1) (или его части) с помощью (2) невозможно.