我拥有包含在shared_ptr中的资源“resource”,我想从其他线程访问它。 当我这样做时:
// foo.h
class Foo{
public:
std::shared_ptr<Setup> GetSomeThing();
void SetSomeThing();
private:
std::shared_ptr<Setup> resource;
std::mutex lock;
}
//Foo.cpp
std::shared_ptr<Setup> Foo::GetSomeThing()
{
std::lock_guard<std::mutex> lock (mutex);
return resource;
}
void Foo::SetSomeThing()
{
std::lock_guard<std::mutex> lock (mutex);
resource = ...;
}
一切都好吗? 什么时候会创建一个返回对象,何时会被锁定?它在文档中是否存在某些内容? 谢谢!
答案 0 :(得分:1)
这个答案假定(为清楚起见)两行:
std::lock_guard<std::mutex> lock (mutex);
都替换为
std::lock_guard<std::mutex> guard (lock);
如果多个线程在没有同步的情况下访问std::shared_ptr<>
的单个实例,并且其中任何一个调用非const
成员,则会发生数据争用。
这意味着您必须确保SetSomeThing()
和GetSomething()
之间的同步。
在提议的方式中引入std::mutex
并使用std::lock_guard<>
即可。返回的副本将在调用guard
的析构函数之前构建。
请注意,它是关于同一个实例的。 GetSomeThing()
返回的副本具有足够的内部同步,以确保无需同步其他实例即可访问(非const
甚至破坏)。
但是,这些都不会阻止Setup
拥有的任何共享std::shared_ptr<Setup>
对象(部分)上的数据争用。如果对Setup
的所有访问都是只读的,则多个线程可以访问它,但如果任何线程写入共享数据,则会发生数据争用(没有进一步同步,问题中没有显示)。
在启动多个线程之前,可以构造和初始化简单应用程序中的Setup
之类的对象,并在除主线程之外的所有线程终止时进行破坏。在那种特定情况下,不需要进一步的同步,甚至提供的锁也是多余的。
这是一个非规范性的参考:
http://en.cppreference.com/w/cpp/memory/shared_ptr
请参阅开场说明的最后一段。
脚注:更改应用程序“设置”可能比仅仅确保属性上不会发生数据争用要困难得多。线程可能需要采用变更或“放弃”活动。例如,考虑一个图形程序,其中在“绘制”步骤期间改变屏幕分辨率。它应该完成绘制并生成一个太大/太小的画布,还是倾倒部分绘制的画布并采用新的分辨率?设置是否以这样的方式获得,即抽奖将产生与“之前”或“之后”一致的东西,而不是一些荒谬的(可能是崩溃的)混合体?