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

时间:2015-01-16 00:58:35

标签: 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和缓存会给处理器缓存带来很多东西,这不是我想知道的......

2 个答案:

答案 0 :(得分:2)

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

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模式:

答案 1 :(得分:1)

高效的单身人士是您的最佳选择。 请点击此处。efficient thread-safe singleton in C++

此外,Herb Sutter talks about that in CppCon 2014

以下是我在上面显示的视频中的完整代码段:

class Foo {
public:
    static Foo* Instance();
private:
    Foo() {init();}
    void init() { cout << "init done." << endl;} // your init cache function.
    static atomic<Foo*> pinstance;
    static mutex m_;
};

atomic<Foo*> Foo::pinstance { nullptr };
std::mutex Foo::m_;

Foo* Foo::Instance() {
  if(pinstance == nullptr) {
    lock_guard<mutex> lock(m_);
    if(pinstance == nullptr) {
        pinstance = new Foo();
    }
  }
  return pinstance;
}

在此处运行代码:http://ideone.com/olvK13