缓存的不可变值:避免锁定

时间:2012-12-03 17:51:31

标签: c++ multithreading caching

假设我有以下代码:

struct Obj {
    mutable bool valueIsCached_;
    mutable int value_;
    const int parameter_;

    Obj (int parameter) : valueIsCached_ (false), parameter_ (parameter) {
    }

    int getValue () const {
        if (!valueIsCached) {
            value_ = calculateValue ();  // #1
            valueIsCached_ = true;       // #2
        }
        return value_;
    }

 private:
    int calculateValue () {
        /* calculate value based on parameter and return it;
           return value only depends on value of parameter_
           (no side effects; no dependence on global state)
        */
    }
 };

如果编译器没有对标记为#1和#2的行重新排序,则此代码显然是线程安全的。可能发生的最糟糕的事情是value_的多次计算。但是,只要我们无法保证在#1之后发生#2,代码就会变得不安全。

  1. 我们怎样才能避免这种情况?
  2. 如果value_的类型是struct,那么事情会变得更糟吗?

1 个答案:

答案 0 :(得分:1)

您需要插入障碍物。这是VC ++的代码:

int getValue () const {
    if (!valueIsCached_) {
        value_ = calculateValue ();  // #1
        _WriteBarrier();             // force value_ to be written first.
        valueIsCached_ = true;       // #2
    }
    return value_;
}

请注意,假设calculateValue是线程安全的,因为它可以由多个线程调用,并且不止一次写入value_valueIsCached_是安全的。