Потокобезопасность с помощью std :: shared_ptr - PullRequest
0 голосов
/ 13 января 2019

Я читал о безопасности потоков в std :: shared_ptr и о перегрузках атомарных операций, которые он обеспечивает, и интересовался конкретным случаем его использования в классе.

Из моего понимания безопасности потоков, которое обещано от shared_ptr, безопасно иметь метод get, подобный так:

class MyClass 
{
std::shared_ptr<int> _obj;
public:
    void start() 
    {
        std::lock_guard<std::mutex> lock(_mtx);
        _obj = std::make_shared<int>(1);
    }

    void stop()
    {
          std::lock_guard<std::mutex> lock(_mtx);
        _obj.reset();

    }
    std::shared_ptr<int> get_obj() const
    {
        return _obj; //Safe (?)
    }
};

Получатель должен быть безопасным, поскольку объект будет либо инициализирован, либо пуст в любой точке из любого потока.

Но что, если я хочу вызвать исключение, если объект пуст, мне нужно проверить его перед возвратом, нужно ли сейчас устанавливать блокировку там (так как stop () может быть вызван между if и return )? Или можно использовать механизм блокировки общего указателя и не использовать блокировку в этом методе:

   std::shared_ptr<int> get_obj() const
    {
        auto tmp = _obj;
        if(!tmp) throw std::exception();
        return tmp;
    }

1 Ответ

0 голосов
/ 13 января 2019

std::shared_ptr экземпляры не являются потокобезопасными. Несколько экземпляров, все указывающие на один и тот же объект, могут быть изменены из нескольких потоков, но один экземпляр не является потокобезопасным. Смотри https://en.cppreference.com/w/cpp/memory/shared_ptr:

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

Поэтому вам необходимо либо заблокировать мьютекс в вашем методе get_obj, либо использовать std::atomic_load и std::atomic_store в ваших start и stop методах

...