关键部分和C ++中的引用返回值

时间:2016-04-05 20:25:10

标签: c++ critical-section

我有一个非常类似的问题已经问过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;
};

问题是,"返回缓存"线路不再受到保护。是否有可能返回"缓存"线程安全参考?

1 个答案:

答案 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,因此另一个线程可能会修改其间的数据并创建竞争条件。