schedule() 影响 OpenMP 中的私有线程变量 #pragma omp parallel for
schedule() affecting private thread variables in OpenMP #pragma omp parallel for
我一直在关注和修改 C/C++ 中的 OpenMP 教程,以演示/理解 schedule()
如何在 #pragma omp parallel for
中工作。
这是我的代码:
#include <unistd.h>
#include <stdlib.h>
#include <omp.h>
#include <stdio.h>
#define THREADS 4
#define N 100
int main ( ) {
int i;
int perThread=0;
printf("Running %d iterations on %d threads.\n", N, THREADS);
#pragma omp parallel for num_threads(THREADS) private(perThread) //schedule(static)
for (i = 0; i < N; i++) {
perThread++;
printf("Thread: %d\t loops: %d\n", omp_get_thread_num(), perThread);
usleep(10000); // to slow the process down a bit
//Uncomment below to simulate one thread taking longer on each loop
// if(omp_get_thread_num()==1)
// sleep(1);
}
// all threads done
printf("All done!\n");
return 0;
}
我将其保存为“schedule_example.cpp”并使用以下命令编译:
g++ schedule_example.cpp -fopenmp -o SheduleEx
然后我将它与未注释的第 13 行 schedule(static)
进行比较,并再次与 schedule()
的各种选项进行比较,即 schedule(static,25)
schedule(static,5)
schedule(dynamic)
schedule(dynamic,5)
schedule(runtime)
调度程序有效,代码显示了差异(特别是当第 20 和 21 行未注释时。)
问题是,对于 schedule()
的某些但不是所有选项,perThread
的起始值对于某些但不是所有线程已更改,这可以在打印输出中看到。
我已经 运行 几台不同机器上的代码,它们都显示了相似的结果。
我在 Windows 10 笔记本电脑 g++ --version
returns 上使用了 WSL:
g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0.
以最后8行为例。如果 schedule()
被注释掉或使用 schedule(static)
输出是正确的:
Thread: 2 loops: 24
Thread: 0 loops: 24
Thread: 1 loops: 24
Thread: 3 loops: 24
Thread: 2 loops: 25
Thread: 1 loops: 25
Thread: 0 loops: 25
Thread: 3 loops: 25
All done!
但是如果我对 shedule()
使用其他任何东西,甚至 schedule(static,25)
应该会给出相同的结果,它会编译并且 运行s 但输出的最后几行是:
Thread: 1 loops: 24
Thread: 3 loops: 24
Thread: 0 loops: 22010
Thread: 2 loops: 24
Thread: 1 loops: 25
Thread: 3 loops: 25
Thread: 0 loops: 22011
Thread: 2 loops: 25
All done!
问题是 perThread
的起始值已设置为 1986 但仅适用于线程 0。
如果我重新运行它,而不重新编译,我得到类似的结果,总是线程 0 是错误的,大约 22000,但每次的数量都不一样。如果我在重新 运行ing 之前重新编译,它会给出相同的结果。
然后我 运行 在 Raspberry Pi 上使用相同的代码并得到相似但略有不同的结果。
g++ --version
returns:
g++ (Raspbian 10.2.1-6+rpi1) 10.2.1 20210110
如果使用 schedule(dynamic)
或 schedule(dynamic, X)
,Raspberry Pi 只会在所有线程上打印出正确的循环值 - 我尝试将 1、5 和 25 作为 X 的值。
如果使用 (static)
或 (static, X)
则除线程 0 之外的所有线程的起始值约为 67321,此数字对于线程 1、2 和 3 始终相同,并且通常但不总是在代码的连续 运行 之间相同。
(auto)
与 (static)
的行为相同。
然而,(runtime)
与 (static)
相反,只有线程 0 是错误的,但也有大约 67481 关闭 - 但是当 运行 连续几次时它是相同的每次金额都不对
我 运行 在另一台装有 Arch Linux 的 PC 上再次使用相同的代码,得到了与 Windows 10 笔记本电脑相似的结果。
就实际问题而言,我的代码编写方式是否有问题?有没有办法确保线程的变量不被改变?
抱歉这么长 post 但我认为问题的核心是 schedule()
以某种方式影响 private()
中一些线程的变量parallel for
循环,有时。
谢谢
您应该使用 firstprivate(perThread)
而不是 private(perThread)
。使用 private
子句声明了您的私有变量,但未对其进行初始化,因此其值未定义。
在OpenMP specification你可以读到
the firstprivate
clause declares one or more list items to be
private to a task, and initializes each of them with the value that
the corresponding original item has when the construct is encountered.
所以你必须使用这个子句。
我一直在关注和修改 C/C++ 中的 OpenMP 教程,以演示/理解 schedule()
如何在 #pragma omp parallel for
中工作。
这是我的代码:
#include <unistd.h>
#include <stdlib.h>
#include <omp.h>
#include <stdio.h>
#define THREADS 4
#define N 100
int main ( ) {
int i;
int perThread=0;
printf("Running %d iterations on %d threads.\n", N, THREADS);
#pragma omp parallel for num_threads(THREADS) private(perThread) //schedule(static)
for (i = 0; i < N; i++) {
perThread++;
printf("Thread: %d\t loops: %d\n", omp_get_thread_num(), perThread);
usleep(10000); // to slow the process down a bit
//Uncomment below to simulate one thread taking longer on each loop
// if(omp_get_thread_num()==1)
// sleep(1);
}
// all threads done
printf("All done!\n");
return 0;
}
我将其保存为“schedule_example.cpp”并使用以下命令编译:
g++ schedule_example.cpp -fopenmp -o SheduleEx
然后我将它与未注释的第 13 行 schedule(static)
进行比较,并再次与 schedule()
的各种选项进行比较,即 schedule(static,25)
schedule(static,5)
schedule(dynamic)
schedule(dynamic,5)
schedule(runtime)
调度程序有效,代码显示了差异(特别是当第 20 和 21 行未注释时。)
问题是,对于 schedule()
的某些但不是所有选项,perThread
的起始值对于某些但不是所有线程已更改,这可以在打印输出中看到。
我已经 运行 几台不同机器上的代码,它们都显示了相似的结果。
我在 Windows 10 笔记本电脑 g++ --version
returns 上使用了 WSL:
g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0.
以最后8行为例。如果 schedule()
被注释掉或使用 schedule(static)
输出是正确的:
Thread: 2 loops: 24
Thread: 0 loops: 24
Thread: 1 loops: 24
Thread: 3 loops: 24
Thread: 2 loops: 25
Thread: 1 loops: 25
Thread: 0 loops: 25
Thread: 3 loops: 25
All done!
但是如果我对 shedule()
使用其他任何东西,甚至 schedule(static,25)
应该会给出相同的结果,它会编译并且 运行s 但输出的最后几行是:
Thread: 1 loops: 24
Thread: 3 loops: 24
Thread: 0 loops: 22010
Thread: 2 loops: 24
Thread: 1 loops: 25
Thread: 3 loops: 25
Thread: 0 loops: 22011
Thread: 2 loops: 25
All done!
问题是 perThread
的起始值已设置为 1986 但仅适用于线程 0。
如果我重新运行它,而不重新编译,我得到类似的结果,总是线程 0 是错误的,大约 22000,但每次的数量都不一样。如果我在重新 运行ing 之前重新编译,它会给出相同的结果。
然后我 运行 在 Raspberry Pi 上使用相同的代码并得到相似但略有不同的结果。
g++ --version
returns:
g++ (Raspbian 10.2.1-6+rpi1) 10.2.1 20210110
如果使用 schedule(dynamic)
或 schedule(dynamic, X)
,Raspberry Pi 只会在所有线程上打印出正确的循环值 - 我尝试将 1、5 和 25 作为 X 的值。
如果使用 (static)
或 (static, X)
则除线程 0 之外的所有线程的起始值约为 67321,此数字对于线程 1、2 和 3 始终相同,并且通常但不总是在代码的连续 运行 之间相同。
(auto)
与 (static)
的行为相同。
然而,(runtime)
与 (static)
相反,只有线程 0 是错误的,但也有大约 67481 关闭 - 但是当 运行 连续几次时它是相同的每次金额都不对
我 运行 在另一台装有 Arch Linux 的 PC 上再次使用相同的代码,得到了与 Windows 10 笔记本电脑相似的结果。
就实际问题而言,我的代码编写方式是否有问题?有没有办法确保线程的变量不被改变?
抱歉这么长 post 但我认为问题的核心是 schedule()
以某种方式影响 private()
中一些线程的变量parallel for
循环,有时。
谢谢
您应该使用 firstprivate(perThread)
而不是 private(perThread)
。使用 private
子句声明了您的私有变量,但未对其进行初始化,因此其值未定义。
在OpenMP specification你可以读到
the
firstprivate
clause declares one or more list items to be private to a task, and initializes each of them with the value that the corresponding original item has when the construct is encountered.
所以你必须使用这个子句。