Я наткнулся на следующий обзор кода StackExchange и решил прочитать его для практики. В коде есть следующее:
Примечание: Я не ищу рецензирование кода, а это просто вставка копии кода из ссылки, чтобы вы могли сосредоточиться на проблеме под рукой без вмешательства другого кода , Я не заинтересован в реализации «умного указателя», просто понимаю модель памяти:
// Copied from the link provided (all inside a class)
unsigned int count;
mutex m_Mutx;
void deref()
{
m_Mutx.lock();
count--;
m_Mutx.unlock();
if (count == 0)
{
delete rawObj;
count = 0;
}
}
Видя это, я сразу же думаю: «Что, если два потока войдут, когда count == 1
и не увидят обновления друг друга? Могут ли оба в конечном итоге увидеть count
как ноль и двойное удаление? И возможно ли для двух потоков: заставить count
стать -1 и тогда удаление никогда не произойдет?
Мьютекс будет гарантировать, что один поток войдет в критическую секцию, однако гарантирует ли это, что все потоки будут должным образом обновлены? Что говорит мне модель памяти C ++, чтобы я мог сказать, что это состояние гонки или нет?
Я посмотрел на страницу cppreference модели памяти и std :: memory_order cppreference , однако последняя страница, похоже, имеет дело с параметром atomic. Я не нашел ответ, который искал, или, возможно, я неправильно его прочитал. Может кто-нибудь сказать мне, если то, что я сказал, является неправильным или правильным, и является ли этот код безопасным или нет?
Для исправления кода, если он сломан:
Правильный ли ответ на этот вопрос, чтобы превратить счет в атомарный член? Или это работает и после снятия блокировки мьютекса все потоки видят значение?
Мне также любопытно, будет ли это правильным ответом:
Примечание: Я не ищу рецензирование кода и не пытаюсь понять, решит ли это решение проблему с моделью памяти C ++.
#include <atomic>
#include <mutex>
struct ClassNameHere {
int* rawObj;
std::atomic<unsigned int> count;
std::mutex mutex;
// ...
void deref()
{
std::scoped_lock lock{mutex};
count--;
if (count == 0)
delete rawObj;
}
};