2015-01-16 18 views
2

我正在使用OpenMP來並行化C++庫。在那裏,我們有許多地方可以避免通過將結果存儲在變量中(即緩存重用結果)來重新計算某些東西。但是,這種行爲在類的方法中對用戶是隱藏的。例如,首次使用方法時,緩存將被填充。所有後續使用只會從緩存中讀取。如何使用多線程處理緩存的數據結構(例如openmp)

我現在的問題是,在一個多線程程序中,多個線程可以同時調用這種方法,從而導致創建/訪問緩存的競爭條件。我目前正在通過將緩存內容放入關鍵部分來解決這個問題,但這當然會拖慢一切。

一個例子類可能會按如下步驟

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版本兼容(甚至v2 for Visual Studio ...)

PS:這可能是以前問過的,但是搜索openmp和caching會在處理器緩存中拋出很多東西,不是我想知道的...

+1

您可以創建一個新的類和全局值那個班級的新手,並且擁有新的Ctor來完成你的初始化? –

+0

在現實生活中,我的對象是set_up在運行時使用不同的參數。當它是set_up時,緩存將被清除,因爲它不再合適。所以,不,我不能有一個全局變量。而且,由於緩存內容的計算時間非常長,並且在所有使用情況下都不需要,所以我們目前避免初始化緩存,除非我們真的需要它。 (你不能從這個問題中知道這一點,我想這是在試圖做一個簡單的例子時發生的)。 – krthie

回答

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

+0

謝謝。我的緩存需要特定於對象,即不是一個單身人士,但我承認這可能不是我的問題。 – krthie

2

您可以使用"Double-Checked-Locking(DCL) pattern"使用OpenMP原子操作,需要OpenMP v3.1或更高版本(read/write選項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模式之一:

+0

在早期版本的openmp中做這件事的機會有多少?我需要儘可能跨平臺兼容。這個解決方案是否克服了DCL模式的問題(參見例如http://michaelsuess.net/publications/suess_leopold_singleton_07.pdf) – krthie

+0

AFAIK,在OpenMP v3.0之前沒有可移植的方式,除了直接使用'omp critical'構造。我認爲這個代碼在OpenMP內存模型下工作良好,因爲'初始化'的訪問被指定爲原子,並且被臨界區保護。 – yohjp

相關問題