我正在考虑实现一种机制来更改程序在运行时使用的最大OpenMP线程数。我的想法是让一个信号处理程序分别捕获SIGUSR1
和SIGUSR2
来增加和减少线程数。由于任何线程都可以随时捕获信号,我可以安全地在信号处理程序中调用omp_set_num_threads()
吗?
答案 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)
值得注意的要点:
只有被调用omp_set_num_threads(2)
的线程生成的嵌套区域的 nthreads-var ICV设置为2.所有其他嵌套区域仍继承原始值4。
对omp_set_num_threads()
的调用不会影响同一嵌套级别的后续并行区域。
只有从程序序列部分调用omp_set_num_threads()
才会影响后续的顶级并行区域。
这里没有显示的事实是,一旦创建了并行区域,就无法更改其团队中的线程数。
因此,如果程序周期性地产生新的并行区域,例如,可以对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
。