2012-12-03 46 views
0

假设我有以下代码:缓存不变的价值:避免锁

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_。但是,只要我们无法保证#2在#1之后发生,代码就会线程不安全。

  1. 我们怎样才能避免这种情况?
  2. 做事情变得更糟如果value_类型是,例如,一个struct
+7

它不是在重新排序书面线程安全的,不管。 –

+1

。试着想象最坏的情况下有两个线程A和B“同时”呼叫'的getValue()':假设一个刚刚执行'如果(valueIsCached!)'和系统决定切换到线程B拥有的方式更高的优先级和执行直到返回value_。现在A可以再次运行,但损坏已经完成。的 – stijn

+0

可能重复[延迟初始化缓存...我如何使它线程安全的?](http://stackoverflow.com/questions/8097439/lazy-initialized-caching-how-do-i-make-it-线程安全) – stijn

回答

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_不止一次是安全的。

+0

非常感谢。这似乎是我一直在寻找的。 – JohnB