我有一个非常类似的问题已经问过2012年。
Critical Sections and return values in C++
我想访问容器线程安全,但是通过引用返回缓存版本。
struct Container {
const Data& getSomeData() const {
EnterCriticalSection(& myCritSec);
if (update) {
cache.calulatefromcontainer();
}
// fill retobj with data from structure
LeaveCriticalSection(& myCritSec);
return cache;
}
private:
mutable Data cache;
};
问题是,"返回缓存"线路不再受到保护。是否有可能返回"缓存"线程安全参考?
答案 0 :(得分:0)
你必须考虑你的关键部分实际上在保护什么。
在您的代码中,myCritSec
似乎正在保护容器。但值得注意的是,不保护cache
成员变量。这不是因为return cache;
行,而是因为您正在返回对它的引用,所以它可以不受客户端代码的限制而使用,而其他线程再次调用getSomeData()
并修改它。
一种解决方案是返回数据副本。
另一个解决方案是,每个可用于从Data
获取信息的公共函数都会以某种方式使用父容器的myCritSec
。这种方法的问题在于它很容易陷入种族。例如:
class Data
{
public:
int getA() const
{
int res;
EnterCriticalSection(parentCS);
res = getAunlocked();
LeaveCriticalSection(parentCS);
return res;
}
int getB() const
{
int res;
EnterCriticalSection(parentCS);
res = getBunlocked();
LeaveCriticalSection(parentCS);
return res;
}
};
然后在用户代码中:
const Data &data = container.getSomeData();
if (data.getA() == data.getB()) // <--- RACE!!!
{
}
由于对getA()
和getB()
的调用分别锁定和解锁CS,因此另一个线程可能会修改其间的数据并创建竞争条件。