Является ли инициализация статической переменной-члена C ++ потокобезопасной?

Согласно следующим ресурсам, в C ++ (особенно Visual C ++) инициализация статической переменной с областью видимости не является потокобезопасной. Но глобальные статические переменные безопасны.

Поточно-ориентированные статические переменные без мьютекса?

http://blogs.msdn.com/oldnewthing/archive/2004/03/08/85901.aspx

Итак, является ли следующий код со статической переменной-членом потокобезопасным?

class TestClass
{
public:
   static MyClass m_instance;
}

Myclass TestClass::m_instance;

Заранее спасибо!


person Varuna    schedule 26.12.2009    source источник
comment
Кажется правдой даже через 5 лет после: blogs.msdn.com/b/vcblog/archive/2013/12/02/ (см. Магическую статику) :)   -  person mlvljr    schedule 21.11.2014
comment
Судя по всему, VS 2015 наконец исправляет это   -  person M.M    schedule 29.12.2015


Ответы (2)


Это больше вопрос статических переменных с функциональной областью и статических переменных любого другого типа, а не глобальных переменных с ограниченной областью видимости.

Все статические переменные, не относящиеся к области функций, создаются перед main (), в то время как активный поток только один. Статические переменные области действия создаются при первом вызове содержащей их функции. В стандарте ничего не говорится о том, как строится статика на уровне функции, когда функция вызывается в нескольких потоках. Однако каждая реализация, с которой я работал, использует блокировку вокруг конструктора (с дважды проверенным флагом), чтобы гарантировать потокобезопасность.

person Marcelo Cantos    schedule 26.12.2009
comment
В стандарте также ничего не говорится о том, как статика без функциональной области строится с использованием нескольких потоков. IIRC все, что гарантируется, - это то, что объект инициализируется до того, как будет выполнен любой другой код в блоке трансляции (то есть код, не вызываемый инициализаторами). Если вы считаете, что код может находиться в DLL, загруженной после начала выполнения main (), вы увидите, что это лучшее, что реально можно гарантировать. Дальнейшие гарантии дает конкретная спецификация потоковой передачи, а не стандарт C ++. - person Steve Jessop; 26.12.2009
comment
g ++ (как в GCC) гарантирует поточно-безопасную инициализацию как глобальных, так и функциональных статических переменных и устанавливает необходимый код для блокировки других потоков во время инициализации. - person Martin York; 26.12.2009
comment
gcc использует блокировки, чтобы сделать статику на уровне функций потокобезопасной (можно отключить с помощью флага). Большинство (все?) Версий Visual C ++ НЕ имеют статики на уровне потоковобезопасных функций. - person tony; 27.12.2009
comment
В C ++ 11 для обеспечения инициализации можно использовать std :: call_once происходит только один раз в потоках. - person Andre Holzner; 11.09.2019

Да(*). Когда глобальная статика инициализируется, есть только один поток, и все конструкторы вызываются в нем. Однако это не относится к статике функции.

(*) Можно сделать глобальную статику небезопасной для потоков, создав потоки в некоторых конструкторах и запланировав некоторые этапы инициализации для этих потоков. В этом случае применяются обычные правила безопасности потоков.

person Rom    schedule 26.12.2009
comment
Я могу создавать потоки в конструкторах, если это последняя программа, которую я пишу ;-) - person Varuna; 26.12.2009
comment
@Varuna: иногда у вас нет выбора или вы даже не знаете, что потоки создаются в ваших конструкторах. Обычно это происходит, когда конструируемые объекты используют сторонние библиотеки. - person Rom; 27.01.2010