简体   繁体   中英

Thread safety of std::shared_ptr<std::mutex>

Consider the following class with a shared_ptr data object. The purpose is to obtain cheaply copyable objects with a data cache shared among the copies.

#include <memory> // std::shared_ptr
#include <mutex> // std::mutex, std::lock_guard

class DataClass {

  std::shared_ptr<DataType> data;
  std::shared_ptr<std::mutex> data_lock;

public:
  DataClass() : data(std::make_shared<DataType>()), data_lock(std::make_shared<std::mutex>()) {}

  DataType get_data() const {
    std::lock_guard<std::mutex> lock_guard(*data_lock);
    if (/* data not cached */) {
      /* calculate and store data */
    }
    return *data;
  }
};

Are calls to get_data() thread-safe? If not, how can that be achieved?

I do have code that seems to end up in a deadlock (far too large/complicated to post), which relies on the above to work fine in parallel calculations.

Are calls to get_data() thread-safe?

As long as data_lock is not modified after the initialization in the DataClass constructor, it is thread-safe. shared_ptr itself is not thread-safe beyond reference counting, meaning that if the pointer itself is modified, it must be protected with a mutex. If it remains constant (which you can ensure by marking data_lock with const ) then multiple threads can read the pointer concurrently, including copying the pointer and incrementing/decrementing the reference counter.

If not, how can that be achieved?

If you do have an instance where data_lock can be modified, you must protect it with a mutex lock or otherwise guarantee that the modification cannot happen while other threads are accessing the pointer. In this particular case this would probably mean to get rid of data_lock pointer and replace it with a mutex.

You should also take care to not allow the pointed object to be accessed after data_lock is modified. Remember that dereferencing shared_ptr returns a raw reference without incrementing the reference counter. If that shared_ptr is modified, the object it previously pointed to can be destroyed and the raw references become dangling. This can happen in a subtle way, eg a reference to the mutex may be saved in a lock_guard , so after you modify data_lock under the lock the lock_guard destructor will attempt to unlock an already destroyed mutex.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM