【问题标题】:How do I ask OpenMP to create threads only once at each run of the program?如何让 OpenMP 在程序每次运行时只创建一次线程?
【发布时间】:2025-12-04 03:10:02
【问题描述】:

我正在尝试并行化由第三方编写的大型程序。我不能透露代码,但我会尝试给出我想做的最接近的例子。 基于下面的代码。如您所见,由于“并行”子句位于 while 循环内部,因此每次迭代都会完成线程的创建/销毁,这是昂贵的。 鉴于我无法将 Initializors...等移到“while”循环之外。

--基础代码

void funcPiece0()
{
    // many lines and branches of code
}


void funcPiece1()
{
    // also many lines and branches of code
}

void funcCore()
{
    funcInitThis();
    funcInitThat();

#pragma omp parallel
    {
#pragma omp sections
        {
#pragma omp section
            {
                funcPiece0();
            }//omp section
#pragma omp section
            {
                funcPiece1();
            }//omp section
        }//omp sections
    }//omp parallel

}

int main()
{

    funcInitThis();
    funcInitThat();
#pragma omp parallel
    {
    while(1)
    {
        funcCore();
    }
    }

}

我想要做的是避免每次迭代的创建/销毁,并在程序的开始/结束时进行一次。我对“并行”子句的置换尝试了许多变化。我基本上具有相同的本质如下:(每个程序运行只有一个线程创建/销毁) --我尝试过,但在初始化函数中“非法访问”失败。

void funcPiece0()
{
    // many lines and branches of code
}


void funcPiece1()
{
    // also many lines and branches of code
}

void funcCore()
{
    funcInitThis();
    funcInitThat();

//#pragma omp parallel
//  {
#pragma omp sections
        {
#pragma omp section
            {
                funcPiece0();
            }//omp section
#pragma omp section
            {
                funcPiece1();
            }//omp section
        }//omp sections
//  }//omp parallel

}

int main()
{

    funcInitThis();
    funcInitThat();

    while(1)
    {
        funcCore();
    }

}

--

任何帮助将不胜感激! 谢谢!

【问题讨论】:

  • 请注意,OpenMP 网站有一个论坛,您可以在其中发布有关 OpenMP 的问题——请访问openmp.org/forum

标签: c multithreading openmp


【解决方案1】:

OpenMP 仅在启动时创建工作线程。并行编译指示不会产生线程。你如何确定线程是产生的?

【讨论】:

  • 感谢您的回答。我的程序挂了,当我用调试器暂停它时,使用我的编译器,我看到许多工作线程正在执行“pragma omp parallel”所在的函数。 “应该”在哪里产生线程?
  • 线程在程序启动时启动(或第一次需要,取决于实现)。在其他任何地方暂停你的程序,你会发现线程仍然存在
  • 虽然我测试的地方似乎是这样(std::this_thread::get_id()omp_get_thread_num() 都显示重复执行并行区域的重复值),但这与官方文档相矛盾,其中它说@ 987654324@ 构造“创建线程”。 openmp.org/spec-html/5.0/openmpse14.html
【解决方案2】:

这是可以做到的!这里的关键是将循环移动到一个单独的并行部分中,并确保无论用于确定是否重复,所有线程都会做出完全相同的决定。我在检查循环条件之前使用了共享变量并进行了同步。

所以这段代码:

initialize();
while (some_condition) {
  #pragma omp parallel
  {
     some_parallel_work();
  }
}

可以转换成这样的:

#pragma omp parallel
{
  #pragma omp single
  {
    initialize();  //if initialization cannot be parallelized
  }
  while (some_condition_using_shared_variable) {
    some_parallel_work();
    update_some_condition_using_shared_variable();
    #pragma omp flush
  }
}

最重要的是确保每个线程在代码中的相同点做出相同的决定。

作为最后的想法,基本上人们正在做的是将创建/销毁线程的开销(每次#pragma omp parallel 的一部分开始/结束)转换为线程决策的同步开销。我认为同步应该更快,但是这里有很多参数在起作用,这可能并不总是如此。

【讨论】: