указатели с OpenMP - PullRequest
       21

указатели с OpenMP

1 голос
/ 28 июня 2011

Я пытаюсь использовать 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. если #pragma omp критическое значение является хорошим решением для push_back()? (Решает ли эта проблема?) Было бы лучше определить для каждого потока свой собственный вектор, а затем объединить их (используя insert ())? или какой-то lock?

  2. В моем исходном коде я получаю сообщение об ошибке: nachbar = Nachbar->Get_Next_Neighbor( &remove_node_v[i] );, но в этом примере нет. Тем не менее, я хотел бы, чтобы OpenMP использовал в качестве числа ядер CNachbarn классов, поскольку CNachbarn является рекурсивным вычислением и не должно зависеть от других потоков. Вопрос в том, как сделать это умнее? (Я не думаю, что было бы разумно определять CNachbarn каждый раз, когда я запускаю цикл for, так как я вызываю эту функцию более миллиона раз в моем моделировании, и время важно.

1 Ответ

4 голосов
/ 09 июля 2011

Относительно вашей первой проблемы: ваша функция Validity - это идеальный способ достижения производительности ниже последовательного в параллельном цикле.Тем не менее, вы уже дали правильный ответ.Вы должны заполнить независимые векторы для каждого потока и объединить их впоследствии.

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

РЕДАКТИРОВАТЬ: Возможное средство может выглядеть следующим образом (если вам требуется последовательный доступ к вашим элементам, вам нужнонемного измените цикл)

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 с размером максимально возможного количества потоков OMP и доступом к отдельным элементам массива из каждого потока, например:

CNachbarn* meine_nachbarn=alle_meine_nachbarn[omp_get_thread_num()]
...