在加锁的函数中,返回值的拷贝是在锁释放前还是锁释放后呢?即返回值的拷贝是否是线程安全的呢?调用者还需要加锁获取返回值吗?
class MyLock
{
public:
using mutex_t = std::mutex;
using lock_t = std::unique_lock<mutex>;
MyLock(mutex_t &mutex) :m_mutex(mutex)
{
m_mutex.lock();
}
~MyLock()
{
m_mutex.unlock();
cout << "[MyLock::~MyLock] destroyed" << endl;
}
private:
mutex_t &m_mutex;
};
class MyData
{
public:
MyData()
{
cout << "[MyData::MyData run]" << endl;
}
MyData(const MyData &d)
{
cout << "[MyData::copy run]" << endl;
}
~MyData()
{
cout << "[MyData::~MyData run]" << endl;
}
int Data() const
{
return m_num;
}
private:
int m_num = 0;
};
class DataMgr
{
public:
using mutex_t = std::mutex;
DataMgr()
{
m_cache[1] = MyData();
}
MyData GetData(int key)
{
MyLock lk(m_mutex);
return m_cache[key];
}
private:
std::map<int, MyData> m_cache;
mutex_t m_mutex;
};
int main(void)
{
DataMgr dm;
auto data = dm.GetData(1);
cout << "get data = " << data.Data() << endl;
}
- 有返回值优化
返回值MyData的拷贝,只有一次,且是在锁释放之前。
- 去掉返回值优化
返回值有两次拷贝,第一次在锁释放之前,第二次在锁释放之后。所以第一次的拷贝是线程安全的,又因为第一次拷贝的变量只会被一个线程使用,所以第二次拷贝,虽然在释放锁之后,但也是线程安全的。
总结
通过上面的测验,我们发现,未持锁的调用者调用持锁函数,返回值的复制是线程安全的。所以多线程环境下,接收返回值为shared_ptr对象,也是线程安全的。