2011-06-28 105 views
1

我想在我的程序中使用OpenMP(我是使用OpenMP的新手),程序在兩處返回錯誤。指針與OpenMP

下面是一個例子代碼:

#include <iostream> 
#include <cstdint> 
#include <vector> 
#include <boost/multi_array.hpp> 
#include <omp.h> 

class CNachbarn { 
public: 
    CNachbarn() { a = 0; } 
    uint32_t Get_Next_Neighbor() { return a++; } 

private: 
    uint32_t a; 
}; 

class CNetwork { 
public: 
    CNetwork (uint32_t num_elements_); 
    ~CNetwork(); 
    void Validity(); 
    void Clean(); 

private: 
    uint32_t num_elements; 
    uint32_t nachbar; 

    std::vector<uint32_t> remove_node_v; 
    CNachbarn *Nachbar; 
}; 

CNetwork::CNetwork(uint32_t num_elements_ ) { 
    num_elements = num_elements_; 
    Nachbar = new CNachbarn(); 

    remove_node_v.reserve(num_elements); 
} 

CNetwork::~CNetwork() { 
    delete Nachbar; 
} 

inline void CNetwork::Validity() { 
    #pragma omp parallel for 
    for (uint32_t i = 0 ; i < num_elements ; i++) { 
     #pragma omp critical 
     remove_node_v.push_back(i); 
    } 
} 

void CNetwork::Clean() { 
    #pragma omp parallel for 
    for (uint8_t j = 0 ; j < 2 ; j++) { 
     nachbar = Nachbar->Get_Next_Neighbor(); 
     std::cout << "i: " << i << ", neighbor: " << nachbar << std::endl; 
    } 

    remove_node_v.clear(); 
} 

int main() { 
    uint32_t num_elements = 1u << 3; 
    uint32_t i   = 0; 
    CNetwork Network(num_elements); 

    do { 
     Network.Validity(); 
     Network.Clean(); 
    } while (++i < 2); 

    return 0; 
} 

我想知道

  1. 如果OMP的#pragma關鍵是push_back()好的解決辦法? (解決這個問題嗎?)爲每個線程定義自己的向量然後將它們合併(使用insert())會更好嗎?或某種lock

  2. 在我原來的代碼中,我得到一個運行錯誤:nachbar = Nachbar->Get_Next_Neighbor(&remove_node_v[i]);但在這個例子中沒有。虛空越少,我想OpenMP使用核心數CNachbarn類,因爲CNachbarn是遞歸計算,不應該受其他線程的影響。問題是如何聰明地做到這一點? (我不認爲這是明智的,每次我開始for循環,因爲我調用這個函數多萬元時代在我的模擬和時間是非常重要的定義CNachbarn

+3

請發佈一個*最小示例*,說明您的問題。你在這裏把所有的工作都交給我們。 –

+0

1.你真的需要一個載體嗎?看起來你可以使用簡單的數組來消除關鍵部分,如果有可能向memset中引入某種「無效」值。然後,您可以掃描該數組並將所有非無效值推送至矢量。根據任務大小的不同,它可以給你一個很大的提升或者根本沒有提升,但是我相信你不會使用OMP進行非耗時的循環。 –

+0

@Konrad,我上傳了一個工作示例 – Eagle

回答

4

關於你的第一個問題: 你功能有效性是實現以下串行性能的並行循環一個完美的方式。然而,你已經給出了正確的答案應填寫獨立矢量爲每個線程,之後將它們合併

inline void CNetwork::Validity() { 
#pragma omp parallel for 
for (uint32_t i = 0 ; i < num_elements ; i++) { 
    #pragma omp critical 
    remove_node_v.push_back(i); 
} 
} 

編輯:。一可能的補救措施可能看起來像這樣(如果你r equire到元素串行訪問,你需要改變回路中的位)

inline void CNetwork::Validity() { 
remove_node_v.reserve(num_elements); 
#pragma omp parallel 
{ 
    std::vector<uint32_t> remove_node_v_thread_local; 
    uint32_t thread_id=omp_get_thread_num(); 
    uint32_t n_threads=omp_get_num_threads(); 
    for (uint32_t i = thread_id ; i < num_elements ; i+=n_threads) 
    remove_node_v_thread_local.push_back(i); 

    #pragma omp critical 
    remove_node_v.insert(remove_node_v.end(), remove_node_v_thread_local.begin(), remove_node_v_thread_local.end()); 
} 
} 

你的第二個問題可以解決通過定義的OMP的最大線程數可能規模,並獲得不同的CNachbarn數組從每個線程的陣列元素,如:

CNachbarn* meine_nachbarn=alle_meine_nachbarn[omp_get_thread_num()] 
+0

我想在每個線程中使用帶有push_back的本地std :: vector,然後將所有本地std :: vectors組合到remove_node_v std :: vector中。我怎麼能這樣做? – Eagle

+0

我編輯了答案以提供可能的解決方案 – FFox