2011-06-28 21 views
1

私のプログラムでOpenMPを使用しようとしています(私はOpenMPを使用している初心者です)。プログラムは2つの場所でエラーを返します。ここで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; 
} 

私はの#pragmaが重要OMP場合

  1. を知っていただきたいと思いpush_back()に適したソリューションですか? (この問題は解決しますか?)スレッドごとに独自のベクトルを定義し、それらを結合する方がよいでしょうか?または何らかの種類の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); 
} 
} 

EDIT:。。。 A可能な救済策はこのように見えるかもしれません(あなたがあなたの要素へのシリアルアクセスをequire、あなたはOMPの最大数は可能なスレッドの大きさ、および個別のアクセス権を持つCNachbarnの配列を定義することによって、あなたの第二の問題は解決できる

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()); 
} 
} 

)ループを少し変更する必要があります

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

私はローカルのstd :: vectorを各スレッドでpush_backと使い、すべてのローカルstd :: vectorsをremove_node_v std :: vectorに組み合わせたいと思っています。どうすればいい? – Eagle

+0

答えを編集して解決策を提示しました – FFox

関連する問題