[英]Is this a correct C++11 double-checked locking version with shared_ptr?
[英]Double-Checked Lock Singleton in C++11
以下單例實現數據 - 競爭是免費的嗎?
static std::atomic<Tp *> m_instance;
...
static Tp &
instance()
{
if (!m_instance.load(std::memory_order_relaxed))
{
std::lock_guard<std::mutex> lock(m_mutex);
if (!m_instance.load(std::memory_order_acquire))
{
Tp * i = new Tp;
m_instance.store(i, std::memory_order_release);
}
}
return * m_instance.load(std::memory_order_relaxed);
}
加載操作的std::memory_model_acquire
是多余的嗎? 是否可以通過將它們切換到std::memory_order_relaxed
來進一步放寬加載和存儲操作? 在這種情況下, std::mutex
的獲取/釋放語義是否足以保證其正確性,或者還需要進一步的std::atomic_thread_fence(std::memory_order_release)
來確保對構造函數的內存的寫入發生在放松的商店? 然而,使用fence相當於使用memory_order_release
存儲?
編輯 :感謝John的回答,我提出了以下應該是數據競爭的實現。 盡管內部負載可能完全是非原子的,但我決定放棄一個寬松的負載,因為它不會影響性能。 與總是具有獲取存儲器順序的外部負載相比,thread_local機器提高了訪問大約一個數量級的實例的性能。
static Tp &
instance()
{
static thread_local Tp *instance;
if (!instance &&
!(instance = m_instance.load(std::memory_order_acquire)))
{
std::lock_guard<std::mutex> lock(m_mutex);
if (!(instance = m_instance.load(std::memory_order_relaxed)))
{
instance = new Tp;
m_instance.store(instance, std::memory_order_release);
}
}
return *instance;
}
我認為這是一個很好的問題,John Calsbeek有正確的答案。
然而,要明確一個懶惰的單身人士最好使用經典的邁耶斯單身人士。 它在C ++ 11中保證了正確的語義。
§6.7.4
...如果控件在初始化變量時同時進入聲明,則並發執行應等待初始化完成。 ...
Meyer的單例是首選,因為編譯器可以積極地優化並發代碼。 如果必須保留std::mutex
的語義,編譯器會受到更多限制。 此外,邁耶的單身是2行 ,幾乎不可能出錯。
這是邁耶的單身人士的典型例子。 簡單,優雅,在c ++ 03中破碎。 但在c ++ 11中簡單,優雅,強大。
class Foo
{
public:
static Foo& instance( void )
{
static Foo s_instance;
return s_instance;
}
};
該實施不是無競爭的。 單例的原子存儲雖然使用了釋放語義,但只會與匹配的獲取操作同步 - 即,已經由互斥鎖保護的加載操作。
在鎖定線程完成初始化單例之前,外部寬松加載可能會讀取非空指針。
另一方面,由鎖保護的獲取是多余的。 它將與另一個線程上具有發布語義的任何商店同步,但此時(由於互斥鎖),可能存儲的唯一線程是當前線程。 這個負載甚至不需要是原子的 - 沒有商店可以從另一個線程發生。
另請參見call_once 。 如果您之前使用單例執行某些操作,但實際上並未將返回的對象用於任何操作,則call_once可能是更好的解決方案。 對於常規單例,你可以做call_once來設置一個(全局?)變量,然后返回那個變量......
為簡潔起見簡化:
template< class Function, class... Args>
void call_once( std::once_flag& flag, Function&& f, Args&& args...);
正好執行一個函數的執行,作為f傳遞給組中的調用(相同的標志對象) 。
在成功完成上述所選功能的執行之前,組中沒有調用返回
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.