【发布时间】:2015-07-16 21:38:14
【问题描述】:
并发写入导致的非确定性读取可以通过以下代码演示:
class Bar {
int val_;
std::mutex m_;
public:
explicit Bar(int v) : val_(v) {}
int val() {
std::lock_guard<std::mutex> l(m_);
return val_;
}
void set(int v) {
std::lock_guard<std::mutex> l(m_);
val_ = v;
}
};
class Foo {
Bar* bar_;
public:
explicit Foo(Bar* bar) : bar_(bar) {}
int val() const { return bar_.val(); }
};
Bar bar(1);
Foo foo(&bar);
cout << foo.val() << endl; // 1
bar.set(2); // probably executed in another thread
cout << foo.val() << endl; // 2
我很想知道避免此类问题的设计模式/编码实践是什么。
我能想到的一个解决方案是制作“深拷贝”,即 Foo 将拥有它所依赖的数据的一致快照,因此所有读取都会得到相同的结果。如果 Foo 拥有 Bar,我们可以将 Bar ref 计数,并让 Foo 维护 Bar 的不同版本的列表(所有对 Bar 的突变都通过 Foo),并且客户端只能获得 Foo 的“快照视图”,它只能访问一个Bar 的版本,即一致的视图。但是,如果 Foo 不拥有 Bar,它就会变得一团糟,我在这里想不出一个好的解决方案。
我的观点是,要么数据所有者需要提供版本化访问权限,要么必须有一个策略强制在读取器发布数据之前不应发生写入。
【问题讨论】:
标签: c++ design-patterns data-structures concurrency mutex