c++ - 如何使用多线程处理缓存数据结构(例如 openmp)

标签 c++ multithreading caching openmp

我正在使用 OpenMP 来并行化我们的 C++ 库。在那里,我们有很多地方可以通过将结果存储在变量中来避免重新计算某些东西(即缓存结果以供重复使用)。但是,这种行为在类的方法中对用户是隐藏的。例如,在第一次使用方法时,缓存将被填充。所有后续使用都将从缓存中读取。

我现在的问题是,在多线程程序中,多个线程可以同时调用这样的方法,导致创建/访问缓存时出现竞争条件。我目前正在通过将缓存内容放在关键部分来解决这个问题,但这当然会减慢一切。

一个示例类可能如下所示

class A {
public:
   A() : initialized(false)
     {}
   int get(int a)
      { 
#pragma omp critical(CACHING)
        if (!initialized)
          initialize_cache();
        return cache[a];
      }
private:
   bool initialized;
   void initialize_cache()
     {
       // do some heavy stuff
       initialized=true;
     }
   int *cache;
};

如果关键部分在 initialize_cache() 函数中会更好,因为那样它只会在缓存尚未初始化时锁定所有线程(即仅一次),但这看起来很危险,因为多个线程可能正在尝试同时初始化缓存。

有什么改进的建议吗?理想情况下,该解决方案将与旧的 OpenMP 版本兼容(甚至是 Visual Studio 的 v2...)

PS:以前可能有人问过这个问题,但是搜索 openmp 和缓存会在处理器缓存上抛出很多东西,这不是我想知道的...

最佳答案

您可以使用 "Double-Checked-Locking(DCL) pattern"使用 OpenMP 原子操作,需要 OpenMP v3.1 或更高版本(omp atomic pragma 的read/write 选项)。

class A {
public:
   A() : initialized(false)
     {}
   int get(int a)
      {
        bool b;
#pragma omp atomic read
        b = initialized;
        if (!b) {
#pragma omp critical(CACHING)
          // you must recheck in critical section
          if (!initialized)
            initialize_cache();
        }
        return cache[a];
      }
private:
   bool initialized;
   void initialize_cache()
     {
       // do some heavy stuff
#pragma omp atomic write
       initialized = true;
     }
   int *cache;
};

...但我推荐以下选项之一而不是 DCL 模式:

关于c++ - 如何使用多线程处理缓存数据结构(例如 openmp),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27975737/

相关文章:

java - Infinispan,版本化操作返回不正确的结果

c++ - 您可以将指针传递给 std::vector 的迭代器吗

c++ - 使用 C++ 正则表达式查找第一个匹配项的索引

multithreading - 在 Delphi 线程中使用 CoInitialize

c# - 使用来自一个特定线程的对象

php - 操作码缓存实际上是如何工作的?

c++ - 与 c++ 中的删除功能混淆

c++ - 字符串到 PCWSTR -> 奇怪的返回(C++)

java - 了解线程安全

caching - Infinispan 与 memcached 满足高并发需求