【问题标题】:Why does the second call of the same function execute forever?为什么同一函数的第二次调用永远执行?
【发布时间】:2021-04-21 12:20:40
【问题描述】:

我编写了一个函数,该函数使用parallel for 以静态时间表进行一些计算,然后返回到我的主程序。之后,我再次调用这个函数,但这次它一直在运行,所以我不得不中止程序。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <omp.h>
#include <time.h>

int thread_count;

void work(int x) {
    int divisor = 0;
    for (int i=1; i<=x; i++) {
        if ((x%i) == 0) {
            divisor++;
        }
    }
}

void initialize(int *codes, int n) {
    thread_count = 4;

    srand(time(NULL));
    for (int i=0; i<n; i++) {
        codes[i] = rand() % 10000;
    }
}

double get_difference(double *times, int n) {
    double min, max;
    min = max = times[0];
    for (int i=1; i<n; i++) {
        if (times[i] > max) {
            max = times[i];
        }
        if (times[i] < min) {
            min = times[i];
        }
    }
    return (max-min);
}

void my_function(int *a, double *times, int n, int thread_count) {
    long i;
    #pragma omp parallel
    {
      #pragma omp parallel for num_threads(thread_count) \
        shared(a, n) private(i) schedule(static, 1)
        for (i=0; i<n; i++) {
            work(a[i]);
        }
        double wtime = omp_get_wtime();
        printf( "Time taken by thread %d is %f\n", omp_get_thread_num(), wtime);
        times[omp_get_thread_num()] = wtime;
     }
}

void odd_even(int *a, int n) {
   int phase, i, tmp;

   # pragma omp parallel num_threads(thread_count) \
      default(none) shared(a, n) private(i, tmp, phase)
   for (phase = 0; phase < n; phase++) {
      if (phase % 2 == 0)
        # pragma omp for 
         for (i = 1; i < n; i += 2) {
            if (a[i-1] < a[i]) {
               tmp = a[i-1];
               a[i-1] = a[i];
               a[i] = tmp;
            }
         }
      else
         #pragma omp for 
         for (i = 1; i < n-1; i += 2) {
            if (a[i] < a[i+1]) {
               tmp = a[i+1];
               a[i+1] = a[i];
               a[i] = tmp;
            }
         }
   }
}

我主要是打电话:

int main(int argc, char *argv[]) {
    int n = atoi(argv[1]);
    int arr[n];
    double times[thread_count];
    initialize(arr, n);
    odd_even(arr, n);
    my_function(arr, times, n, thread_count);
    double difference = get_difference(times, thread_count);
    printf("Difference is %f\n", difference);

    // my_function(arr, times, n, thread_count);
    // difference = get_difference(times, thread_count);
    // printf("Difference is %f\n", difference);
}

我对标准输出进行了一些打印,它会在几秒钟内为第一次调用顺利打印每个线程的时间戳,但是当我进行第二次调用时,程序将永远执行并且什么都不会打印。

我尝试了调度块大小为 n/thread_count 的块分布和块大小为 1 的块循环分布,但无论哪种方式我都会遇到相同的问题。

我也尝试过复制该函数,并一个接一个地调用具有相同内容的两个不同函数,但这也不起作用。

我没有更改两次调用之间的任何变量和数据,那么为什么第二个函数调用没有正确执行?

【问题讨论】:

    标签: c multithreading performance parallel-processing openmp


    【解决方案1】:

    您的代码存在一些问题,在函数my_function 中,循环的迭代没有按照您的意愿分配给线程。因为您再次将子句parallel 添加到#pragma omp for,并假设您禁用了嵌套并行性,默认情况下,在外部并行区域中创建的每个线程都将“按顺序”执行该区域内的代码.因此,对于n = 6number of threads = 4,您将拥有以下代码块:

    for (i=0; i<n; i++) {
        work(a[i]);
    }
    

    正在执行6 x 4 = 24 次(循环迭代的总数乘以线程总数)。如需更深入的解释,请查看此SO Thread 关于类似问题。然而,下图提供了基本要素的可视化:

    因此将my_function 修复为:

    void my_function(int *a, double *times, int n, int thread_count) {
        # pragma omp parallel num_threads(thread_count) shared(a)
        {
           #pragma omp for schedule(static, 1)
           for (long i=0; i<n; i++) {
               work(a[i]);
           }
        double wtime = omp_get_wtime();
        printf( "Time taken by thread %d is %f\n", omp_get_thread_num(), wtime);
        times[omp_get_thread_num()] = wtime;
        }
    }
    

    其次,变量在被正确初始化之前正在使用thread_count

    double times[thread_count];
    initialize(arr, n);
    

    改为:

    initialize(arr, n);
    double times[thread_count];
    

    最后一个问题是导致undefined behavior,这可能会导致无法预料的问题。

    另一个您可能知道或不知道的问题是讽刺地函数work实际上并没有做任何有意义的事情

    单独调用double wtime = omp_get_wtime(); 不会告诉您线程工作了多长时间。 According to the OpenMP documentation

    omp_get_wtime 例程以秒为单位返回经过的挂钟时间。

    因此,要衡量在某些代码块中花费的时间,您可以执行以下操作

    double begin = omp_get_wtime();
    // block of code
    double end = omp_get_wtime();
    

    并使用表达式end-begin 以秒为单位获取时间。在你的情况下:

     void my_function(int *a, double *times, int n, int thread_count) {
            # pragma omp parallel num_threads(thread_count) shared(a)
            {
               double begin = omp_get_wtime();
               #pragma omp for schedule(static, 1)
               for (long i=0; i<n; i++) {
                   work(a[i]);
               }
               double end = omp_get_wtime();
               double time = end - begin;
               printf( "Time taken by thread %d is %f\n", omp_get_thread_num(), time);
               times[omp_get_thread_num()] = time;
            }
        }
    

    【讨论】:

      猜你喜欢
      • 2011-01-20
      • 2013-04-08
      • 1970-01-01
      • 1970-01-01
      • 2022-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多