wikipedia :: Double-checked locking
От: kaa.python Ниоткуда РСДН профессионально мёртв и завален ватой.
Дата: 13.12.19 01:22
Оценка:
По мотивам одного из срачей
Автор: aik
Дата: 13.12.19
, я наткнулся на несколько озадачевшею меня реализацию Double-checked locking:
#include <atomic>
#include <mutex>

class Singleton {
 public:
  Singleton* GetInstance();

 private:
  Singleton() = default;

  static std::atomic<Singleton*> s_instance;
  static std::mutex s_mutex;
};

Singleton* Singleton::GetInstance() {
  Singleton* p = s_instance.load(std::memory_order_acquire);
  if (p == nullptr) {
    std::lock_guard<std::mutex> lock(s_mutex);
    p = s_instance.load(std::memory_order_relaxed);    // <- это
    if (p == nullptr) {
      p = new Singleton();
      s_instance.store(p, std::memory_order_release);
    }
  }
  return p;
}


В принципе всё логично и работать оно будет, но какой в данном случае смысл в std::memory_order_relaxed под мьютексом? Мьютекс же работает как барьер и в любом случае чтение пройдет как std::memory_order_acquire? Или я что-то путаю?
Отредактировано 13.12.2019 1:23 kaa.python . Предыдущая версия .
Re: wikipedia :: Double-checked locking
От: σ  
Дата: 13.12.19 01:56
Оценка:
KP>В принципе всё логично и работать оно будет, но какой в данном случае смысл в std::memory_order_relaxed под мьютексом? Мьютекс же работает как барьер и в любом случае чтение пройдет как std::memory_order_acquire? Или я что-то путаю?

Умение задавать вопросы в которых 100% ответа — это своего рода талант.
Re[2]: wikipedia :: Double-checked locking
От: kaa.python Ниоткуда РСДН профессионально мёртв и завален ватой.
Дата: 13.12.19 02:00
Оценка:
Здравствуйте, σ, Вы писали:

KP>>В принципе всё логично и работать оно будет, но какой в данном случае смысл в std::memory_order_relaxed под мьютексом? Мьютекс же работает как барьер и в любом случае чтение пройдет как std::memory_order_acquire? Или я что-то путаю?


σ>Умение задавать вопросы в которых 100% ответа — это своего рода талант.


Re: wikipedia :: Double-checked locking
От: Шахтер Интернет  
Дата: 13.12.19 05:58
Оценка: +1
Здравствуйте, kaa.python, Вы писали:

KP>По мотивам одного из срачей
Автор: aik
Дата: 13.12.19
, я наткнулся на несколько озадачевшею меня реализацию Double-checked locking:

KP>
KP>#include <atomic>
KP>#include <mutex>

KP>class Singleton {
KP> public:
KP>  Singleton* GetInstance();

KP> private:
KP>  Singleton() = default;

KP>  static std::atomic<Singleton*> s_instance;
KP>  static std::mutex s_mutex;
KP>};

KP>Singleton* Singleton::GetInstance() {
KP>  Singleton* p = s_instance.load(std::memory_order_acquire);
KP>  if (p == nullptr) {
KP>    std::lock_guard<std::mutex> lock(s_mutex);
KP>    p = s_instance.load(std::memory_order_relaxed);    // <- это
KP>    if (p == nullptr) {
KP>      p = new Singleton();
KP>      s_instance.store(p, std::memory_order_release);
KP>    }
KP>  }
KP>  return p;
KP>}
KP>


KP>В принципе всё логично и работать оно будет, но какой в данном случае смысл в std::memory_order_relaxed под мьютексом? Мьютекс же работает как барьер и в любом случае чтение пройдет как std::memory_order_acquire? Или я что-то путаю?


Это оптимизация. memory_order_relaxed -- самый дешёвый вид чтения. На x86 это просто считывание переменной. Поскольку оно происходит под мьютексом, никаких дополнительных гарантий не нужно.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[2]: wikipedia :: Double-checked locking
От: kaa.python Ниоткуда РСДН профессионально мёртв и завален ватой.
Дата: 13.12.19 06:16
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Это оптимизация. memory_order_relaxed -- самый дешёвый вид чтения. На x86 это просто считывание переменной. Поскольку оно происходит под мьютексом, никаких дополнительных гарантий не нужно.


Я немного о другом. Разве мьютекс не является одновременно барьером? Если он является таковым, то memory_order_relaxed в данном случае не вносит никакой оптимизации.

Если же утверждение выше не верно, то хотелось бы понять каким образом memory_order_relaxed привносит здесь оптимизацию?
Re[3]: wikipedia :: Double-checked locking
От: Шахтер Интернет  
Дата: 13.12.19 08:27
Оценка: 9 (1) +1
Здравствуйте, kaa.python, Вы писали:

KP>Здравствуйте, Шахтер, Вы писали:


Ш>>Это оптимизация. memory_order_relaxed -- самый дешёвый вид чтения. На x86 это просто считывание переменной. Поскольку оно происходит под мьютексом, никаких дополнительных гарантий не нужно.


KP>Я немного о другом. Разве мьютекс не является одновременно барьером? Если он является таковым, то memory_order_relaxed в данном случае не вносит никакой оптимизации.


KP>Если же утверждение выше не верно, то хотелось бы понять каким образом memory_order_relaxed привносит здесь оптимизацию?


Я не понимаю, чего здесь не понятного? Для считывания атомика нужно вызвать load с флагом. Флаг определяет дополнительные телодвижения, которые компилятор сгенерирует для соблюдения соответствующих гарантий.
Самый дешёвый флаг memory_order_relaxed. Он даёт только одну гарантию -- атомарность операции.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re: А смысл?
От: landerhigh Пират  
Дата: 13.12.19 08:47
Оценка: -1
Здравствуйте, kaa.python, Вы писали:

KP>По мотивам одного из срачей
Автор: aik
Дата: 13.12.19
, я наткнулся на несколько озадачевшею меня реализацию Double-checked locking:


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

Короче, за что боремся?
www.blinnov.com
Re[2]: А смысл?
От: kaa.python Ниоткуда РСДН профессионально мёртв и завален ватой.
Дата: 13.12.19 08:54
Оценка:
Здравствуйте, landerhigh, Вы писали:

L>Короче, за что боремся?


Да меня сама конструкция заинтересовала, вариант использования std::memory_order_relaxed. Так что можно считать это не вопросом про синглтон, а вопросом про std::memory_order_relaxed и мьютексы
Re: wikipedia :: Double-checked locking
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 13.12.19 09:56
Оценка: 18 (1) +1 :)
Здравствуйте, kaa.python, Вы писали:

KP>В принципе всё логично и работать оно будет, но какой в данном случае смысл в std::memory_order_relaxed под мьютексом? Мьютекс же работает как барьер и в любом случае чтение пройдет как std::memory_order_acquire? Или я что-то путаю?


Acquire был раньше, когда мьютекс захватывался. А теперь можно, пока под мьютексом, прочесть максимально дешёвым и быстрым образом и не получить за это по рыжей морде каким-нибудь обгоном. Поэтому — relaxed.
Иначе бы получалось, что мьютекс уже захвачен, и снова вдруг подымается машина сериализации операций — а нафига собственно?
The God is real, unless declared integer.
Re[4]: wikipedia :: Double-checked locking
От: $$ Австралия жж
Дата: 13.12.19 12:21
Оценка: :)
Здравствуйте, Шахтер, Вы писали:

Ш>Я не понимаю, чего здесь не понятного? Для считывания атомика нужно вызвать load с флагом.


Почему бы обычный volatile не использовать? Ведь буков меньше и на до- C++11 компиляторах соберётся.
Re[5]: wikipedia :: Double-checked locking
От: Vamp Россия  
Дата: 13.12.19 13:28
Оценка: +1 -1
Здравствуйте, $$, Вы писали:

$>Здравствуйте, Шахтер, Вы писали:

Ш>>Я не понимаю, чего здесь не понятного? Для считывания атомика нужно вызвать load с флагом.


$>Почему бы обычный volatile не использовать? Ведь буков меньше и на до- C++11 компиляторах соберётся.
Не ожидал такого вопроса в 2019 году... Рекомендую обратиться к первоисточникам.
Да здравствует мыло душистое и веревка пушистая.
Re: wikipedia :: Double-checked locking
От: Vamp Россия  
Дата: 13.12.19 13:34
Оценка: +1 -1
Про релаксед вроде объяснили. А вот на икса нам вообще нужен СимплСинглтон нуждается в дополнительном сра обсуждении.
Да здравствует мыло душистое и веревка пушистая.
Re[5]: wikipedia :: Double-checked locking
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 13.12.19 14:33
Оценка:
Здравствуйте, $$, Вы писали:

$>Здравствуйте, Шахтер, Вы писали:

Ш>>Я не понимаю, чего здесь не понятного? Для считывания атомика нужно вызвать load с флагом.


$>Почему бы обычный volatile не использовать?

Потому что volatile делает совсем не то, что надо.

$>Ведь буков меньше и на до- C++11 компиляторах соберётся.

До C++11 можно было платформенно-зависимые функции применять.
The God is real, unless declared integer.
Re[6]: wikipedia :: Double-checked locking
От: Videoman Россия https://hts.tv/
Дата: 13.12.19 15:24
Оценка: -1
Здравствуйте, Vamp, Вы писали:

V>$>Почему бы обычный volatile не использовать? Ведь буков меньше и на до- C++11 компиляторах соберётся.

V>Не ожидал такого вопроса в 2019 году... Рекомендую обратиться к первоисточникам.

Безотносительно того, что volatile тут не поможет, хотелось бы заметить, что по коду сразу не понятно в каком году он написан, но судя по тому что в нем все еще гуляют голые указатели, а не std::unique_ptr — явно раньше 11-го года
И вообще, в С++11 уже давно появился std::call_once, который без лишних вопросов, должен решить проблему создания одного объекта.
Отредактировано 13.12.2019 15:26 Videoman . Предыдущая версия . Еще …
Отредактировано 13.12.2019 15:25 Videoman . Предыдущая версия .
Re[2]: wikipedia :: Double-checked locking
От: sergey2b ЮАР  
Дата: 13.12.19 15:33
Оценка:
Здравствуйте, netch80, Вы писали:

N>Acquire был раньше, когда мьютекс захватывался. А теперь можно, пока под мьютексом, прочесть максимально дешёвым и быстрым образом и не получить за это по рыжей морде каким-нибудь обгоном. Поэтому — relaxed.

N>Иначе бы получалось, что мьютекс уже захвачен, и снова вдруг подымается машина сериализации операций — а нафига собственно?

а где нибудь можно про это почитать в систематизированном виде ?
те не в викпедии
Re[3]: wikipedia :: Double-checked locking
От: PM  
Дата: 13.12.19 15:46
Оценка: 10 (1)
Здравствуйте, sergey2b, Вы писали:

S>а где нибудь можно про это почитать в систематизированном виде ?

S>те не в викпедии

Про потокобезопасное создание singleton? Подробный разбор был в https://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/

Про memory order у атомарных инструкций? На https://en.cppreference.com/w/cpp/atomic/memory_order неплохо написано.

Про многопоточность в С++ вообще? C++ Concurrency in Action by Anthony Williams
Re[3]: wikipedia :: Double-checked locking
От: Vamp Россия  
Дата: 13.12.19 15:56
Оценка: 10 (1)
Здравствуйте, sergey2b, Вы писали:

S>Здравствуйте, netch80, Вы писали:


N>>Acquire был раньше, когда мьютекс захватывался. А теперь можно, пока под мьютексом, прочесть максимально дешёвым и быстрым образом и не получить за это по рыжей морде каким-нибудь обгоном. Поэтому — relaxed.

N>>Иначе бы получалось, что мьютекс уже захвачен, и снова вдруг подымается машина сериализации операций — а нафига собственно?

S>а где нибудь можно про это почитать в систематизированном виде ?

S>те не в викпедии

Вот тут неплохо: https://stackoverflow.com/questions/6319146/c11-introduced-a-standardized-memory-model-what-does-it-mean-and-how-is-it-g
Да здравствует мыло душистое и веревка пушистая.
Re[7]: wikipedia :: Double-checked locking
От: reversecode google
Дата: 13.12.19 15:58
Оценка:
static Object gObj;
Re[6]: wikipedia :: Double-checked locking
От: $$ Австралия жж
Дата: 14.12.19 02:26
Оценка:
Здравствуйте, netch80, Вы писали:

N>До C++11 можно было платформенно-зависимые функции применять.

Ага, InterlockedExchange. Подзабыл уже.

На Java достаточно volatile.
Re[7]: wikipedia :: Double-checked locking
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 14.12.19 09:54
Оценка:
Здравствуйте, $$, Вы писали:

$>Здравствуйте, netch80, Вы писали:

N>>До C++11 можно было платформенно-зависимые функции применять.

$>Ага, InterlockedExchange. Подзабыл уже.

При чём тут это? InterlockedExchange не имеет уже никакого смысла, если мы под мьютексом, который защищает доступ к переменной (и все участники соблюдают это). Он нужен, если мы стараемся обойти без мьютекса — но в этом случае в C++11 есть свой atomic_exchange.
Про платформенно-зависимые я имел в виду, что где-то pthread_mutex_lock, где-то WaitForSingleObject над мьютексом.

А вы таки путаетесь в самых основах, лучше повторить.

$>На Java достаточно volatile.

И снова мимо. Явовский volatile ближе всего к std::atomic<> load/store с memory_order_seq_cst.
Но он не даст защиты больше чем на одно чтение/запись. Аналог доступа под мьютексом — это synchronized.
The God is real, unless declared integer.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.