Как вернуть вывод каждого потока в массив, используя OpenMP? - PullRequest
0 голосов
/ 21 января 2019

Я хотел бы продолжить многопоточную программу, где каждый поток выводит массив с неизвестным количеством элементов.

Например, выберите все числа, которые <10, из массива int и поместите их в новый массив. </p>

Псевдокод (8 потоков):

  int *hugeList = malloc(10000000);
  for (long i = 0; i < 1000000; ++i)
  {
      hugeList[i] = (rand() % 100);//random integers from 0 to 99
  }
  long *subList[8];//to fill each thread's result
  #pragma omp parallel
  for (long i = 0; i < 1000000; ++i)
  {
     long n = 0;
     if(hugeList[i] < 10)
     {
        //do something to fill "subList" properly
        subList[threadNo][n] = hugeList[i];
        n++;
     }
  }

Массив "subList" должен собирать элементы в "огромный список", который удовлетворяет условию (<10), последовательно и с точки зрения номера потока. </p>

Как мне написать код? Это нормально, если есть лучший способ использования OpenMP.

Ответы [ 2 ]

0 голосов
/ 22 января 2019

Обновлены полные коды на основе ответа @Alain Merigot. Я протестировал следующий код;Это воспроизводимо (включая наличие и отсутствие аргументов #pragma).Тем не менее, только передние элементы subList верны, а остальные пусты.(filename.c)

#include <stdio.h>
#include <time.h>
#include <omp.h>
#include <stdlib.h>
#include <math.h>
#define HUGE 10000000
#define DELAY 1000 //depends on your CPU power

//use global variables to store desired results, otherwise can't be obtain outside "pragma"
int n = 0;// number of results. We want one per thread to only have local updates.
double *subList;// table to hold thread results

int main()
{
    double *hugeList = (double *)malloc(HUGE);
#ifdef _OPENMP
    int thread_nbr = omp_get_max_threads();
#else
    int thread_nbr = 1; // to ensure proper behavior in a sequential context
#endif

    struct thread_results
    {                    // to hold per thread results
        int nbr;         // nbr of generated results
        double *results; // actual filtered numbers. Will write in subList table
    };

    // could be parallelized, but rand is not thread safe. drand48 should be
    for (long i = 0; i < 1000000; ++i)
    {
        hugeList[i] = sin(i); //fixed array content to test reproducibility
    }

    subList = (double *)malloc(HUGE * sizeof(double)); // table to hold thread results
                                                        // this is more complex to have a 2D array here as max_thread and actual number of thread
                                                        // are not known at compile time. VLA cannot be used (and array dim can be very large).
                                                        // Concerning its size, it is possible to have ALL elements in hugeList selected and the array must be
                                                        // dimensionned accordingly to avoid bugs.
    struct thread_results *threadres = (struct thread_results *)malloc(thread_nbr * sizeof(struct thread_results));

#pragma omp parallel
    {
// first declare and initialize thread vars
#ifdef _OPENMP
        int thread_id = omp_get_thread_num();   // hold thread id
        int thread_nbr = omp_get_num_threads(); // hold actual nbr of threads
#else
        // to ensure proper serial behavior
        int thread_id = 0;
        int thread_nbr = 1;
#endif

        struct thread_results *res = threadres + thread_id;
        res->nbr = 0;
        // compute address in subList table
        res->results = subList + (HUGE / thread_nbr) * thread_id;
        double *res_ptr = res->results; // local pointer. Each thread points to independent part of subList table

#pragma omp for reduction(+ \
                          : n)
        for (long i = 0; i < 1000000; ++i)
        {
            for (int i = 0; i < DELAY; ++i){}//do nothing, just waste time

            if (hugeList[i] < 0)
            {
                //do something to fill "subList" properly
                res_ptr[n] = hugeList[i];
                n++;
            }
        }
        res->nbr = n;
    }
    for (int i = 0; i < 10; ++i)
    {
        printf("sublist %d: %lf\n", i, subList[i]);//show some elements of subList to check reproducibility
    }
    printf("n = %d\n", n);
}

Компиляция Linux: gcc -o имя_файла filename.c -fopenmp -lm

Надеюсь, можно еще обсудить механизм этого кода.

0 голосов
/ 21 января 2019

В вашем коде есть несколько проблем.

1 / Прагма omp должна быть параллельной, если вы хотите, чтобы цикл for был распараллелен.В противном случае код будет продублирован в каждом потоке.

2 / код не соответствует комментарию

  //do something to fill "subList" properly
   hugeList[i] = subList[threadNo][n];

3 / Как узнать количество элементов в ваших подсписках?Он должен быть возвращен в основной поток.Вы можете использовать массив, но остерегайтесь ложного обмена.Лучше использовать локальную переменную и записать ее в конце параллельного раздела.

4 / sublist не выделен.Сложность в том, что вы не знаете количество потоков.Вы можете задать omp максимальное количество потоков (get_omp_max_thread) и выполнить динамическое распределение.Если вам нужно статическое распределение, возможно, лучше всего выделить большую таблицу и вычислить фактический адрес в каждом потоке.

5 / код omp также должен работать без компилятора openmp.Для этого используйте #ifdef _OPENMP.

Вот (непроверенный) способ написания вашего кода

#define HUGE 10000000
int *hugeList = (int *) malloc(HUGE);
#ifdef _OPENMP
int thread_nbr=omp_get_max_threads();
#else
int thread_nbr=1; // to ensure proper behavior in a sequential context
#endif

struct thread_results { // to hold per thread results
  int nbr; // nbr of generated results
  int *results; // actual filtered numbers. Will write in subList table
};

// could be parallelized, but rand is not thread safe. drand48 should be
for (long i = 0; i < 1000000; ++i)
  {
    hugeList[i] = (rand() % 100);//random integers from 0 to 99
  }

int *subList=(int *)malloc(HUGE*sizeof(int)); // table to hold thread results
   // this is more complex to have a 2D array here as max_thread and actual number of thread
   // are not known at compile time. VLA cannot be used (and array dim can be very large).
   // Concerning its size, it is possible to have ALL elements in hugeList selected and the array must be
   // dimensionned accordingly to avoid bugs.
struct thread_results* threadres=(struct thread_results *)malloc(thread_nbr*sizeof(struct thread_results));

#pragma omp parallel
{
// first declare and initialize thread vars
#ifdef _OPENMP
  int thread_id = omp_get_thread_num() ; // hold thread id
  int thread_nbr = omp_get_num_threads() ; // hold actual nbr of threads
#else
  // to ensure proper serial behavior
  int thread_id = 0;
  int thread_nbr = 1;
#endif

  struct thread_results *res=threadres+thread_id;
  res->nbr=0;
  // compute address in subList table
  res->results=subList+(HUGE/thread_nbr)*thread_id;
  int * res_ptr=res->results; // local pointer. Each thread points to independent part of subList table

  int n=0; // number of results. We want one per thread to only have local updates.
  #pragma omp for
  for (long i = 0; i < 1000000; ++i)
  {

     if(hugeList[i] < 10)
     {
      //do something to fill "subList" properly
       res_ptr[n]=hugeList[i];
       n++;
     }
  }
  res->nbr=n;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...