шаблон блокировки с двойной проверкой

В C ++ и опасностях двойной проверки блокировки есть персональный код для правильной реализации шаблона, предложенный авторами. См. Ниже,

Singleton* Singleton::instance () {
    Singleton* tmp = pInstance;
    ... // insert memory barrier (1)
    if (tmp == 0) {
        Lock lock;
        tmp = pInstance;
        if (tmp == 0) {
            tmp = new Singleton;
            ... // insert memory barrier (2)
            pInstance = tmp;
        }
    }
    return tmp;
}

Мне просто интересно, можно ли переместить первый барьер памяти прямо над оператором return?

РЕДАКТИРОВАТЬ : Другой вопрос: В связанной статье, как vidstige , цитируется

Технически вам не нужны полные двунаправленные барьеры. Первый барьер должен предотвратить миграцию вниз конструкции Синглтона (другой веткой); второй барьер должен предотвратить миграцию вверх инициализации pInstance. Они называются «приобретать» и "Освободить" операции, и может дать лучшую производительность, чем полная барьеры на оборудовании (например, Itainum), которое делает различие.

В нем говорится, что второй барьер не должен быть двунаправленным, так как он может предотвратить перемещение назначения pInstance перед этим барьером? Хотя первый барьер может предотвратить миграцию вверх, но другой поток все еще может иметь шанс увидеть неинициализированные члены.

РЕДАКТИРОВАТЬ : Я думаю, что почти понимаю цель первого барьера. Как отметил sonicoder , предсказание ветвления может привести к тому, что tmp будет NULL, когда if возвращает истину. Чтобы избежать этой проблемы, должен быть барьер получения, чтобы предотвратить чтение tmp взамен перед чтением в if.

Первый барьер соединен со вторым барьером для достижения отношения синхронизация с , поэтому его можно сдвинуть вниз.

РЕДАКТИРОВАТЬ : Тем, кто интересуется этим вопросом, настоятельно рекомендую прочитать memory-barriers.txt .

12
задан Community 23 May 2017 в 12:31
поделиться