OpenMP 任务优先私有

OpenMP task firstprivate

如果我们假设以下代码,我有一个关于 OpenMP 任务编译指示的问题:

#pragma omp parallel
{
 x = omp_get_thread_num();

#pragma omp task firstprivate(x)
//do something with x

}

据我了解任务分配,不能保证哪个线程执行任务。 所以我的问题是,任务中的“x”现在是生成任务的线程 ID 还是执行任务的线程 ID?

例如如果线程 0 遇到任务,线程 3 执行它:那么 x 应该是 0,对吗?

So my question is, is "x" in the task now the id of thread generated the task or the one who executes it?

这取决于,如果 parallel 默认 data-sharing 属性是 shared(默认情况下通常是)然后:

  • 'x'可以等于任意线程ID,范围从0到组内线程总数-1。这是因为变量[=51=更新时存在竞争条件].

这可以是show-cased,代码如下:

#include <omp.h>
#include <stdio.h>
int main(){
    int x;
    #pragma omp parallel
    {
        x = omp_get_thread_num();

        if(omp_get_thread_num() == 1){
                sleep(5);
                #pragma omp task firstprivate(x)
                {       
                   printf("Value of x = %d | ID Thread executing = %d\n", x, omp_get_thread_num());
                }
        }

    }
    return 0;
}

因此具有 ID=1 的线程创建任务,但是,'x' 可以具有与“1”不同的值,也可以与当前执行任务的线程具有不同的值。这是因为 ID=1 的线程在 sleep(5); 期间等待时,团队中的其余线程可以更新 'x'.

的值

通常,这种 use-cases 中的规范形式是使用 single pragma 环绕任务创建,如下所示:

#include <omp.h>
#include <stdio.h>
int main(){
    int x;
    #pragma omp parallel
    {
        #pragma omp single
        {
                printf("I am the task creator '%d'\n", omp_get_thread_num());
                x = omp_get_thread_num();
                #pragma omp task firstprivate(x)
                {       
                        printf("Value of x = %d | ID Thread executing = %d\n", x, omp_get_thread_num());
                }
        }

    }
    return 0;
}

在这种情况下,@Michael Klemm 在评论中提到:

..., x 将包含创建任务的线程的 ID。所以,是的,如果线程 0 创建了任务,即使选择线程 3 来执行任务,x 也将为零。

这也适用于变量 'x' 在语句 x = omp_get_thread_num(); 发生时是私有的情况。

因此,如果您 运行 上面的代码,您应该始终获得与 Value of x = 具有相同值的 I am the task creator,但您可以在 ID Thread executing 中获得不同的值.例如:

I am the task creator '4'
Value of x = 4 | ID Thread executing = 7

这符合 OpenMP 标准中指定的行为,即:

The task construct is a task generating construct. When a thread encounters a task construct, an explicit task is generated from the code for the associated structured block. The data environment of the task is created according to the data-sharing attribute clauses on the task construct, per-data environment ICVs, and any defaults that apply.

The encountering thread may immediately execute the task, or defer its execution. In the latter case, any thread in the team may be assigned the task.