Защита потоков инициализации статической переменной
Я хочу узнать, являются ли 2 обращения к Get()
с разными типами параметров в приведенном ниже коде потокобезопасными:
struct MethodTypeIndex
{
template <typename T>
static size_t Get(T)
{
static size_t index = NextIndex();
return index;
}
private:
static size_t NextIndex()
{
static size_t nextIndex = 0;
return nextIndex++;
}
};
С одной стороны, NextIndex()
вызывается во время инициализации index
и в соответствии со стандартом:
§6.7 [stmt.dcl] p4
Если элемент управления входит в объявление одновременно, а переменная будучи инициализированным, одновременное выполнение должно ждать завершения инициализации.
С другой стороны, я не знаю, рассматривается ли вызов NextIndex()
как часть инициализации index
. А если нет, то делает ли инициализация скобок?
static size_t index{ NextIndex() };
Или есть ли другие способы сделать его потокобезопасным, если я не хочу сделать nextIndex
atomic?
Ответы
Ответ 1
Притворись, что у вас есть две разные функции:
static size_t get_int() {
static size_t index = NextIndex();
return index;
}
static size_t get_long() {
static size_t index = NextIndex();
return index;
}
Есть ли сомнения в том, что вызов этих двух функций из отдельных потоков не потокобезопасен? Очевидно, что это гонка данных при вызовах NextIndex
.
Создание этих функций путем создания экземпляра функции шаблона не избавляет от гонки данных. Шаблоны не являются кодом; они шаблоны для создания кода. Вызов двух разных экземпляров вашей функции шаблона (например, Get<int>()
и Get<long>()
) из двух разных потоков приводит к расходу данных.