嵌套的openMP并行化与std :: thread结合使用

时间:2014-07-28 07:58:32

标签: c++ multithreading c++11 openmp stdthread

你好StackOverFlowers,

我目前正致力于图像处理领域的更大项目。我正在使用Visual Studio 2013开发(不可协商)。没有任何进一步的细节困扰你,这是我的问题:

我有两个必须并行运行的动作:

  1. 线性方程组的迭代解(使用1-2个线程)

  2. 涉及图像到图像注册的相当复杂的过程。 (使用所有剩余的线程)

  3. 为了知道需要注册哪些图像,需要线性方程组的近似解。因此他们需要同时运行。 (感谢Z boson指出缺少这些信息)。迭代解决方案不断运行,并在每次成功的图像注册后获得通知。

    代码将在24核系统上运行。

    目前使用openMP和" #pragma omp parallel for"实现图像注册。 迭代解决方案正在使用std :: thread启动,并且还使用openMP" #pragma omp parallel for"内部。

    现在我知道,根据the omp documentation,找到嵌套并行性的omp线程将使用其线程团队来执行代码。但我认为这在我的情况下不起作用,因为它的std :: thread会启动第二个omp-parallelism。

    为了更好地理解,这里是一个示例代码:

    int main()
    {
        std::thread * m_Thread = new std::thread(&IterativeSolution);
    
        #pragma omp parallel for
        for(int a = 0; a < 100; a++)
        {
            int b = GetImageFromApproximateSolution();
            RegisterImages(a,b);
            // Inform IterativeSolution about result of registration
        }
    }
    
    void IterativeSolution()
    {
        #pragma omp parallel for
        for(int i = 0; i < 2; i++)
        {
            //SolveColumn(i);
        }
    }
    void RegisterImage(int a, int b)
    {
        // Do Registration
    }
    

    我现在的问题是:上面的代码会创建太多线程吗?如果是这样,以下代码会解决问题吗?

    int main()
    {
        // The max is to avoid having less than 1 thread
        int numThreads = max(omp_get_max_threads() - 2, 1); 
    
        std::thread * m_Thread = new std::thread(&IterativeSolution);
    
        #pragma omp parallel for num_threads(numThreads)
        for(int a = 0; a < 100; a++)
        {
            int b = GetImageFromApproximateSolution();
            RegisterImages(a,b);
            // Inform IterativeSolution about result of registration
        }
    }
    
    void IterativeSolution()
    {
        #pragma omp parallel for num_threads(2)
        for(int i = 0; i < 2; i++)
        {
            //SolveColumn(i);
        }
    }
    void RegisterImage(int a, int b)
    {
        // Do Registration
    }
    

1 个答案:

答案 0 :(得分:2)

这会在OpenMP标准方面产生未定义的行为。我测试的大多数实现将在第一个示例中为这两个并行区域中的每一个创建24个线程,总共48个。第二个示例不应创建太多线程,但由于它依赖于未定义的行为,因此可能会发生崩溃在没有警告的情况下将计算机变成果冻状物质。

由于您已经在使用OpenMP,我建议您通过简单地删除std :: thread并使用嵌套的OpenMP并行区域来使其符合标准OpenMP。你可以这样做:

int main()
{
    // The max is to avoid having less than 1 thread
    int numThreads = max(omp_get_max_threads() - 2, 1); 
    #pragma omp parallel num_threads(2)
    {
        if(omp_get_thread_num() > 0){
            IterativeSolution();
        }else{
            #pragma omp parallel for num_threads(numThreads)
            for(int a = 0; a < 100; a++)
            {
                int b = GetImageFromApproximateSolution();
                RegisterImages(a,b);
                // Inform IterativeSolution about result of registration
            }
        }
    }
}

void IterativeSolution()
{
    #pragma omp parallel for num_threads(2)
    for(int i = 0; i < 2; i++)
    {
        //SolveColumn(i);
    }
}
void RegisterImage(int a, int b)
{
    // Do Registration
}

您可能需要将环境变量定义OMP_NESTED=trueOMP_MAX_ACTIVE_LEVELS=2或更多内容添加到您的环境中以启用嵌套区域。此版本具有在OpenMP中完全定义的优点,并且应该在支持嵌套并行区域的任何环境上可移植。如果您的版本不支持嵌套的OpenMP并行区域,那么您建议的解决方案可能是最佳选择。