如何使用 OpenMP 生成单个线程(如 std::thread())并随后使用“#pragma omp single”和“#pragma omp for”?

问题描述 投票:0回答:1

我只想生成一个后台线程,例如 std::thread,但仅使用 OpenMP。 这可能吗? 如果是的话,是怎么做到的? 为了更好地解释我想要实现的目标,这里是我想要做的 C++ 代码:

//05.06.2024
//How to spawn a single thread with OpenMP (like a std::thread()) and use "#pragma omp single" and 
//"#pragma omp for" afterwards? This here does not work! (as expected)
//OS: Linux Mint 21.3, Kernel: 6.5.0-35-generic x86_64 bits
//compiler: g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0

// g++ -O2 openmp_single_bkgtask_test.cpp -fopenmp 

#include <omp.h>
#include <iostream>
#include <unistd.h>

void backgroundWork()
{
    while(true)
    {
        std::cout<<"background work!"<<std::endl;
        usleep(1e6);
    }   
}

int main()
{           
    omp_set_num_threads(8); 
        
    #pragma omp parallel
    {
        #pragma omp single nowait
        #pragma omp task
        backgroundWork();
                
        while(true)
        {
            #pragma omp single
            std::cout<<"loading data"<<std::endl;
            //++++++++++
            //prog never comes beyond this point, because "#pragma omp single" is waiting after
            //"loading data" for the <task>-thread to finish (which of course does not happen
            //++++++++++
            #pragma omp for
            for(int i=0;i<16;i++)
            {
                std::cout<<"processing data "<<i<<std::endl;
            }                   
        }       
    }           
    
    return 0;
}

我知道这行不通,因为 omp 单指令将等待所有线程,但“任务”中“缺少”一个线程,因此它按预期“工作”。 但如何在 OpenMP 中生成线程?

task openmp pragma stdthread
1个回答
1
投票

这是仅使用任务的解决方案,以及整个并行区域的

omp single
编译指示:

int main()
{           

    #pragma omp parallel
    #pragma omp single
    {
        #pragma omp task
        backgroundWork();
                
        int v = 0;
        while(true)
        {
            v++;
            #pragma omp critical
            std::cout<<v<<" loading data"<<std::endl;
            #pragma omp taskloop
            for(int i=0;i<4;i++)
            {
                usleep(1e5);
                #pragma omp critical
                std::cout<<v<<" processing data "<<i<<std::endl;
            }                   
        }
    }           
    
    return 0;
}

根据 Jerôme Richard 的建议,将

omp for
替换为
omp taskloop
critical
编译指示只是为了更好地格式化文本输出。

由于执行

single
区域的线程在任务循环执行期间不执行任何操作,因此与核心数量相比,您可以多使用一个线程。另一种情况是后台任务几乎不执行任何操作。

请注意,实际上并不能保证后台任务首先执行(允许 OpenMP 运行时自行调度任务),尽管实际上很有可能是这样。保证执行的另一种选择是基于部分:

int main()
{           

    #pragma omp parallel sections
    {
        #pragma omp section
        backgroundWork();
                
        #pragma omp section
        {
            int v = 0;
            while(true)
            {
                v++;
                #pragma omp critical
                std::cout<<v<<" loading data"<<std::endl;
                #pragma omp taskloop
                for(int i=0;i<4;i++)
                {
                    usleep(1e5);
                    #pragma omp critical
                    std::cout<<v<<" processing data "<<i<<std::endl;
                }   
            }                
        }
    }           
    
    return 0;
}

带有部分和嵌套并行性的第三种解决方案:

int main()
{           

    omp_set_nested(1);

    #pragma omp parallel sections num_threads(2)
    {
        #pragma omp section
        backgroundWork();
                
        #pragma omp section
        {
            int v = 0;
            while(true)
            {
                v++;
                #pragma omp critical
                std::cout<<v<<" loading data "<<omp_get_thread_num()<<std::endl;
                #pragma omp parallel for num_threads(2)
                for(int i=0;i<4;i++)
                {
                    usleep(1e5);
                    #pragma omp critical
                    std::cout<<v<<" processing data "<<i<<" "<<omp_get_thread_num()<<std::endl;
                }   
            }                
        }
    }           
    
    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.