← Назад к вопросам
Потокобезопасен ли shared_ptr?
2.3 Middle🔥 191 комментариев
#Умные указатели и управление памятью#Многопоточность и синхронизация
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Потокобезопасность shared_ptr
Этот вопрос часто вызывает путаницу, потому что ответ подразумевает уточнение: shared_ptr потокобезопасен частично.
Что потокобезопасно
Операции над счётчиком ссылок — атомарны:
std::shared_ptr<int> ptr1 = std::make_shared<int>(42);
std::shared_ptr<int> ptr2;
// Поток 1
ptr2 = ptr1; // атомарная операция захвата счётчика
// Поток 2
std::shared_ptr<int> ptr3 = ptr1; // тоже безопасно
Потокобезопасны:
- Копирование shared_ptr
- Перемещение (move)
- Захват и отпуск счётчика ссылок
- get(), use_count()
Что НЕ потокобезопасно
Доступ к управляемому объекту:
std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>();
// Поток 1
ptr->method(); // NOT THREAD-SAFE
// Поток 2
ptr->method(); // Может произойти race condition на данных MyClass
Присваивание нескольким потокам:
std::shared_ptr<int> shared;
// Поток 1
shared = std::make_shared<int>(1); // Читает и пишет указатель
// Поток 2
shared = std::make_shared<int>(2); // Race condition!
Правильный порядок синхронизации
std::shared_ptr<MyClass> shared;
std::mutex mtx;
void update() {
auto new_obj = std::make_shared<MyClass>();
{
std::lock_guard<std::mutex> lock(mtx);
shared = new_obj; // Присваивание под блокировкой
}
}
void use() {
std::shared_ptr<MyClass> local;
{
std::lock_guard<std::mutex> lock(mtx);
local = shared; // Копируем под блокировкой
}
// Теперь можем работать с local без блокировки
if (local) {
local->method();
}
}
Почему это важно
Счётчик ссылок — внутреннее состояние shared_ptr, его целостность гарантирована атомарными операциями. Но:
- Структура shared_ptr содержит два указателя (на контрольный блок и объект)
- Присваивание shared_ptr — не атомарная операция на уровне самого shared_ptr
- Гарантия распространяется только на счётчик, не на сам указатель
Вывод
- shared_ptr безопасен для читателей одного указателя с разными потоками
- shared_ptr БЕЗ СИНХРОНИЗАЦИИ — если изменяются присваивания переменной
- Объект, на который указывает shared_ptr — требует отдельной синхронизации
- Используй мьютекс вокруг присваиваний и чтения shared_ptr из разных потоков