OpenMP-二进制树

OpenMP - Binary tree

本文关键字:二进制 OpenMP-      更新时间:2023-10-16

我正在尝试运行一个简单的程序来并行运行。我想把它建立在二叉树的基础上。根据处理器的数量,我想将工作分配给所有处理器,以便程序并行运行。使用递归,我会检查是否还有1或2个处理器,如果有,我会使用OpenMP sections来运行它。然而,它使用的内核越多,算法就越慢,我不明白为什么。我试着写尽可能不言自明的代码。

void fun1(int tab[], int pocz, int kon, int threadsLeft)
{
    if (threadsLeft == 2)
    {
        #pragma omp parallel num_threads(2)
        {
            #pragma omp sections nowait
            {
                #pragma omp section
                {
                    for (int i = pocz; i < kon/2; i++)
                    {
                        tab[i] = 1;
                    }
                }
                #pragma omp section
                {
                    for(int i = kon/2 + 1; i < kon; i++)
                    {
                        tab[i] = 0;
                    }
                }
            }
        }
    }
    else if (threadsLeft == 1)
    {
        #pragma omp parallel num_threads(1)
        {
            #pragma omp sections nowait
            {
                #pragma omp section
                {
                    for (int i = pocz; i < kon; i++)
                    {
                        tab[i] = 2;
                    }
                }
            }
        }
    }
    else
    {
        fun1(tab, pocz, kon/2, threadsLeft/2);
        fun1(tab, kon - kon/2, kon, threadsLeft - threadsLeft / 2);
    }
}
int main()
{
    int allThreads = omp_get_num_threads();
    int N = 200000000;
    int* tab = new int[N];
    for (int i = 0; i < N; i++)
    {
        tab[i] = 0;
    }
    fun1(tab, 0, N, allThreads);
}

在我看来,您有两个问题。

第一个问题是,在主函数中,在平行区域之外,omp_get_num_threads()应该总是返回1。因此,在一个平行区域内调用它,以便访问您当前平行区域的线程数量。

第二个问题是,您有一个递归问题,它有助于实现任务并行性。OpenMP sections最好与常数先验已知数量的节一起使用。OpenMP tasks设计用于处理递归问题,其中您想要生成的任务的数量不一定是已知的。例如,请查看本基本教程。请注意,编译器必须支持OpenMP 3.0才能正常工作。

将这两者放在一起,您的新#pragma omp tasks代码应该如下所示:

void fun1(int tab[], int pocz, int kon, int threadsLeft)
{
    if (threadsLeft <= 1) {
        for (int i = pocz; i < kon; i++)
            tab[i] = 2; // should make this constant something else to be more helpful
    }
    else
    {
        #pragma omp task
        fun1(tab, pocz, kon/2, threadsLeft/2);
        #pragma omp task
        fun1(tab, kon - kon/2, kon, threadsLeft - threadsLeft/2);
        #pragma omp taskwait
    }
}
int main()
{
    int N = 200000000;
    int* tab = new int[N];
    for (int i = 0; i < N; i++)
        tab[i] = 0;
    #pragma omp parallel
    // Only the first thread will spawn other threads
    #pragma omp single nowait
    {
        int allThreads = omp_get_num_threads();
        fun1(tab, 0, N, allThreads);
    }
}

公平的警告:我自己还没有测试过这个代码,所以对此持谨慎态度。