Так что я кое-что прочитал: https://en.wikipedia.org/wiki/Double-checked_locking и http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/. Я нашел этот код для его использованияДвойная проверка блокировки: Заборы и атомизация
std::atomic<Singleton*> Singleton::m_instance;
std::mutex Singleton::m_mutex;
Singleton* Singleton::getInstance() {
Singleton* tmp = m_instance.load(std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_acquire);
if (tmp == nullptr) {
std::lock_guard<std::mutex> lock(m_mutex);
tmp = m_instance.load(std::memory_order_relaxed);
if (tmp == nullptr) {
tmp = new Singleton;
std::atomic_thread_fence(std::memory_order_release);
m_instance.store(tmp, std::memory_order_relaxed);
}
}
return tmp;
}
и есть одно, что мне непонятно. Работает ли он иначе, чем следующий код без заборов?
std::atomic<Singleton*> Singleton::m_instance;
std::mutex Singleton::m_mutex;
Singleton* Singleton::getInstance() {
Singleton* tmp = m_instance.load(std::memory_order_acquire);
if (tmp == nullptr) {
std::lock_guard<std::mutex> lock(m_mutex);
tmp = m_instance.load(std::memory_order_acquire);
if (tmp == nullptr) {
tmp = new Singleton;
m_instance.store(tmp, std::memory_order_release);
}
}
return tmp;
}
Что я имею в виду, если я заменяю заборы соответствующим порядком памяти в load/store, работает ли он так же?
Удобно, когда вы используете C++ 11, есть ** нет ** нужно использовать любое из этого! Просто используйте это: 'Singleton * Singleton :: getInstance() {static Singleton rc; return &rc;} 'Функционально-локальные переменные' static' инициализируются в потокобезопасном режиме для начала. Обратите внимание, что этот комментарий не считается одобрением синглтонов: он является анти-шаблоном, и, на мой взгляд, нет места для одиночек, тем более в параллельном коде. –
У этой конструкции есть два недостатка для меня: 1) в Visual Studio 2012 это не фактически безопасный поток AFAIK 2) вы не можете избавиться от созданного таким образом одноэлементного кода до конца вашей программы – Paladin
Если вы действительно хотите «удалить» объект , вы * можете * использовать указатель и выделить его: инициализация по-прежнему является потокобезопасной: 'static Singleton * rc = new Singleton();'. Независимо от того, инициализирует ли MSVC++ 2012 функцию локальную статику или нет, я не знаю: я предпочитаю не использовать разбитые компиляторы. –