Est la suivante singleton mise en œuvre des données de course gratuit?
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);
}
Est l' std::memory_model_acquire
de l'opération de chargement superflu? Est-il possible de se détendre à la fois de la charge et des opérations de banque par commutation à std::memory_order_relaxed
? Dans ce cas, est l'acquisition/diffusion sémantique std::mutex
suffisant pour garantir son exactitude, ou un autre std::atomic_thread_fence(std::memory_order_release)
est également nécessaire pour s'assurer que les écritures dans la mémoire du constructeur se produire avant que l'atmosphère détendue de la boutique? Pourtant, c'est l'utilisation de la clôture de l'équivalent d'avoir le magasin avec memory_order_release
?
EDIT: Merci pour la réponse de Jean, je suis venu avec la suite de la mise en œuvre qui devraient être données à la course libre. Même si l'intérieur de la charge pourrait être non-atomique à tous, j'ai décidé de partir une ambiance détendue charge en ce qu'elle n'affecte pas les performances. En comparaison, afin de toujours avoir une charge externe avec l'acquisition de la mémoire de commande, le thread_local machines améliore les performances de l'accès à l'instance d'environ un ordre de grandeur.
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;
}