Подтвердить что ты не робот

Защита потоков инициализации статической переменной

Я хочу узнать, являются ли 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?

4b9b3361

Ответ 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>()) из двух разных потоков приводит к расходу данных.