c++ - C++11 中的无锁缓存实现

标签 c++ multithreading c++11 caching lock-free

C++11 中是否有任何方法可以为对象实现无锁缓存,并且可以安全地从多个线程访问该对象?我要缓存的计算不是 super 便宜,但也不是 super 昂贵,因此在我的情况下,需要锁定会破坏缓存的目的。 IIUC,std::atomic 不保证无锁。

编辑:由于计算并不是太昂贵,所以我实际上不介意它是否运行一次或两次太多。但我确实需要确保所有消费者都能获得正确的值(value)。在下面的简单示例中,无法保证这一点,因为由于内存重新排序,线程可能会获得未初始化的 m_val 值,因为另一个线程将 m_alreadyCalculated 设置为true,但尚未设置 m_val 的值。

Edit2:下面的注释指出,对于基本类型,std::atomic 可能是无锁的。如果是,下面示例中使用 C++11 的内存排序来确保 m_alreadyCalculated 不可能在 m_val 之前设置为 true 的正确方法是什么code> 的值设置了吗?

非线程安全缓存示例:

class C {
public:
   C(int param) : m_param(param) {}

   getValue() {
      if (!m_alreadyCalculated) {
          m_val = calculate(m_param);
          m_alreadyCalculated = true;
      }
      return m_val;
   }

   double calculate(int param) {
       // Some calculation
   }

private:
   int m_param;
   double m_val;
   bool m_alreadyCalculated = false;
}

最佳答案

将某事视为:

class C {
public:
   double getValue() {
      if (alreadyCalculated == true)
         return m_val;

      bool expected = false;
      if (calculationInProgress.compare_exchange_strong(expected, true)) {
         m_val = calculate(m_param);
         alreadyCalculated = true;
      // calculationInProgress = false;
      }
      else {
     //  while (calculationInProgress == true)
         while (alreadyCalculated == false)
            ; // spin
      }
      return m_val;
   }

private:
   double m_val;
   std::atomic<bool> alreadyCalculated {false};
   std::atomic<bool> calculationInProgress {false};
};

其实它并不是无锁的,里面有一个自旋锁。但我认为如果你不想运行 calculate() 你就无法避免这样的锁。通过多线程。

getValue()这里变得更加复杂,但重要的部分是一旦 m_val计算后,总是会立即返回第一个if声明。

更新

出于性能原因,将整个类填充到缓存行大小可能也是一个好主意。

更新2

原始答案中有一个错误,感谢 JVApen 指出这一点(已用评论标记)。变量calculationInProgress最好重命名为 calculationHasStarted .

另外,请注意,此解决方案假设 calculate()不抛出异常。

关于c++ - C++11 中的无锁缓存实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36239880/

相关文章:

c++ - 数据结构/容器选择

c++ - 用于 C++ 代码的控制流图生成器

c++ 整数的幂,模板元编程

java - 如何在 Java 中设计线程化的 UDP 客户端/服务器?

java - 如何在多个线程之间安全地共享 ArrayDeque?

C++函数映射实现

c++ - 如何在我的 dll 接口(interface)或 ABI 中使用标准库 (STL) 类?

c++ - 如何排序 std::vector 忽略某些数字?

c# - 为什么不用 GOTO 语句?

c++ - 多线程和 MFC