Назад к вопросам
Middle
116
questionbank

Является ли shared_ptr потокобезопасным и можно ли использовать его в контексте нескольких потоков?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

Да, shared_ptr потокобезопасен для операций инкремента/декремента счетчика ссылок. Это означает, что множество потоков могут одновременно копировать или уничтожать shared_ptr к одному и тому же ресурсу без гонки данных на самом счетчике.

Однако доступ к управляемому объекту данных через несколько shared_ptr из разных потоков не является потокобезопасным по умолчанию. Если разные потоки читают и/или модифицируют этот объект одновременно, вам необходимо использовать дополнительные механизмы синхронизации (например, мьютексы) для защиты самого объекта.

Использование shared_ptr в многопоточном контексте возможно и часто необходимо, но требует понимания того, какая часть shared_ptr (счетчик) потокобезопасна, а какая (доступ к данным) — нет.

#include <iostream>
#include <memory>
#include <thread>
#include <vector>
#include <mutex> // Для синхронизации доступа к данным

struct Data {
    int value;
    std::mutex mutex; // Мьютекс для защиты value

    Data(int v) : value(v) {}
};

int main() {
    auto shared_data = std::make_shared<Data>(0);

    auto increment = [&](std::shared_ptr<Data> ptr) {
        // Доступен из разных потоков - счетчик ссылок потокобезопасен
        std::lock_guard<std::mutex> lock(ptr->mutex); // Защита доступа к value
        ptr->value++;
    };

    std::vector<std::thread> threads;
    int num_threads = 10;

    for (int i = 0; i < num_threads; ++i) {
        threads.emplace_back(increment, shared_data); // Передача копии shared_ptr
    }

    for (auto& t : threads) {
        t.join();
    }

    std::cout << "Final value: " << shared_data->value << std::endl; // Должно быть 10

    return 0;
}