是omp_set_num_threads线程安全吗?

时间:2014-01-21 00:18:17

标签: multithreading thread-safety signals openmp

我正在考虑实现一种机制来更改程序在运行时使用的最大OpenMP线程数。我的想法是让一个信号处理程序分别捕获SIGUSR1SIGUSR2来增加和减少线程数。由于任何线程都可以随时捕获信号,我可以安全地在信号处理程序中调用omp_set_num_threads()吗?

1 个答案:

答案 0 :(得分:2)

每个数据环境中 nthreads-var ICV的值都是从其父环境中复制的。对来自并行区域内的 nthreads-var 的更改,例如:通过调用omp_set_num_threads(),仅影响由omp_set_num_threads()调用的线程启动的嵌套并行区域。

检查以下代码:

#include <stdio.h>
#include <omp.h>

int main (void)
{
  omp_set_num_threads(4);
  omp_set_nested(1);
  #pragma omp parallel
  {
    #pragma omp single
    {
      printf("First region, nthreads-var = %d\n", omp_get_num_threads());
      omp_set_num_threads(2);
    }
    #pragma omp parallel
    {
      #pragma omp single
      printf("Nested region, nthreads-var = %d\n", omp_get_num_threads());
    }
  }
  #pragma omp parallel
  {
    #pragma omp single
    printf("Second region, nthreads-var = %d\n", omp_get_num_threads());
  }
  omp_set_num_threads(2);
  #pragma omp parallel
  {
    #pragma omp single
    printf("Third region, nthreads-var = %d\n", omp_get_num_threads());
  }
  return 0;
}

其输出如下:

First region, nthreads-var = 4
Nested region, nthreads-var = 2  <--- (1)
Nested region, nthreads-var = 4
Nested region, nthreads-var = 4
Nested region, nthreads-var = 4
Second region, nthreads-var = 4  <--- (2)
Third region, nthreads-var = 2   <--- (3)

值得注意的要点:

  1. 只有被调用omp_set_num_threads(2)的线程生成的嵌套区域的 nthreads-var ICV设置为2.所有其他嵌套区域仍继承原始值4。

  2. omp_set_num_threads()的调用不会影响同一嵌套级别的后续并行区域。

  3. 只有从程序序列部分调用omp_set_num_threads()才会影响后续的顶级并行区域。

  4. 这里没有显示的事实是,一旦创建了并行区域,就无法更改其团队中的线程数。

    因此,如果程序周期性地产生新的并行区域,例如,可以对OpenMP线程的数量进行运行时控制。在一个大循环中。在这种情况下,可以捕获信号并使用所需线程数的值操纵全局变量:

    volatile int g_num_threads;
    
    void sighandler(int signum)
    {
      switch (signum)
      {
        case SIGUSR1:
          g_num_threads++;
          break;
        case SIGUSR2:
          g_num_threads--;
          break;
      }
    }
    
    // The following loop is NOT part of a parallel region
    while (some_condition)
    {
       omp_set_num_threads(g_num_threads);
       #pragma omp parallel
       {
          // Do some work
       }
    }
    

    或者,可以使用num_threads子句将线程数设置为g_num_threads