дважды проверенная схема блокировки - PullRequest
12 голосов
/ 19 февраля 2011

В 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 цитируется

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

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

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

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

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

Ответы [ 2 ]

5 голосов
/ 19 августа 2014

Я не нашел здесь правильного ответа, связанного с вашим вопросом, поэтому я решил опубликовать его даже спустя более трех лет;)

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

Да, может.

Это для потоков, которые не будут вводить оператор if, т. Е. pInstance уже создан и правильно инициализирован и является видимым.

Второй барьер (тот, что перед pInstance = tmp;) гарантирует, что инициализация полей членов синглтона фиксируется в памяти до pInstance = tmp;. Но это не обязательно означает, что другие потоки (на других ядрах) будут видеть эти эффекты памяти в том же порядке (нелогично, верно?). Второй поток может видеть новое значение указателя в кеше, но не эти поля-члены. Когда он обращается к члену путем разыменования указателя (например, p->data), адрес этого члена, возможно, уже был в кеше, но не тот, который требуется. Взрыв! Неправильные данные читаются. Обратите внимание, что это более чем теоретически. Существуют системы , для которых необходимо выполнить инструкцию когерентности кэша (например, барьер памяти), чтобы извлечь новые данные из памяти.

Вот почему первый барьер существует. Это также объясняет, почему можно поместить его прямо перед оператором return (но это должно быть после Singleton* tmp = pInstance;).

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

Барьер записи гарантирует, что каждой предшествующей записи будет происходить перед каждой записью, следующей за ней . Это знак остановки, и никакая запись не может пересечь его на другую сторону. Для более подробного описания см. здесь .

4 голосов
/ 19 февраля 2011

Нет, барьер памяти нельзя перемещать ниже оператора присваивания, поскольку барьер памяти защищает назначение от миграции вверх.Из связанной статьи:

Первый барьер должен предотвращать миграцию конструкции Синглтона вниз (другим потоком);второй барьер должен предотвращать миграцию инициализации pInstance вверх.

С другой стороны: двойная проверка блокирующих шаблонов для синглетонов полезна, только если у вас огромные требования к производительности.

Профилировали ли вы свои двоичные файлы и наблюдали ли доступ к синглтону как узкое место?Если нет вероятности, вам вообще не нужно беспокоиться о двойной проверке схемы блокировки.

Я рекомендую использовать простую блокировку.

...