c++ - OpenMP - 使用 nowait 运行单个区域,然后在 for 循环中加入其他线程
问题描述
我想做的是函数的第一部分在一个线程中运行,其他线程启动第二个函数(这个函数有三个循环),在单线程结束第一个函数后,他与其他人一起帮助循环。
我编写了以下代码,这是错误的,因为所有线程都运行第二个函数,并且只需要一个即可运行,但所有线程都有助于循环。
void main(){
/* code */
#pragma omp parallel
{
#pragma omp single nowait
{
std::cout << "Running func 1:" << omp_get_thread_num() << std::endl;
func1();
std::cout << "Finish func 1" <<std::endl;
}
#pragma omp nowait
std::cout << "Running func 2:" << omp_get_thread_num() << std::endl;
func2();
#pragma omp barrier
}//close parallel
/* more code */
}//close main
void func2(void){
/* code to read file */
#pragma omp parallel
{
for (int i=40;i<60;i++){
#pragma omp for nowait
for (int j=0;j<100;j++){
/* code */
}
}
#pragma omp for schedule(dynamic,1) nowait
for (int i=0;i<40;i++){
for (int j=0;j<100;j++){
/* code */
}
}
#pragma omp for schedule(dynamic)
for (int i=60;i<100;i++){
for (int j=0;j<100;j++){
/* code */
}
}
/* code to write file */
}//close parallel
#pragma omp barrier
} //close func2
我的终端显示:
Running func 1: 0
Running func 2: 1
Running func 2: 2
Running func 2: 3
Finish func 1
Running func 2: 0
编辑
Obs.: Func1 应该只在一个线程上执行
func2 被分成三个 for 循环,因为第一个 for 比其他所有循环消耗更多的时间。如果我只使用一个 for 循环,所有其他线程将结束,一些线程将继续运行。这样,首先计算困难。
使用 Jim Cownie 建议的代码,func1 和 func2 并行运行,但是要么线程运行 func2 两次,要么只有一个线程单独运行而无需其他线程的帮助。
即使有必要使用任务或部分,我有什么想法吗?
解决方案
您的代码有很多问题
- 没有这样的 openMP 指令
#pragma omp nowait
,因此您甚至可能没有在启用 OpenMP 的情况下进行编译(因为,当它启用时,您应该收到一条错误消息;例如,请参阅https://godbolt.org/z/EbYV6h) #pragma omp barrier
在并行区域结束之前永远不需要 a (因为将执行下一个串行区域的主线程不能离开,直到所有线程也完成在并行区域中的执行。)
我不明白你为什么要使用嵌套并行。您已经在并行执行 func2() ,因此此处的任何嵌套都会导致超额订阅。
你可以像这样实现你想要的
#pragma omp parallel
{
#pragma omp single nowait
func1()
func2();
}
void func2()
{
#pragma omp for schedule(dynamic), nowait
for (...)
... etc ...
}
或者,通过使用任务和任务循环,这可能是一种更简洁的表达方式。
使用任务,(并且,在您澄清您只想function2
执行一次之后(我正在阅读代码所说的,因为这比读心术更容易!)),这样的事情有效
#include <unistd.h>
#include <stdio.h>
#include <omp.h>
void function1()
{
fprintf(stderr,"%d: entering function1\n", omp_get_thread_num());
sleep(1);
fprintf(stderr,"%d: leaving function1\n", omp_get_thread_num());
}
void function2()
{
fprintf(stderr,"%d: entering function2\n", omp_get_thread_num());
#pragma omp taskloop grainsize(1)
for (int i=0; i<10; i++)
{
fprintf(stderr,"%d: starting iteration %d\n",
omp_get_thread_num(),i);
sleep(1);
fprintf(stderr,"%d: finishing iteration %d\n",
omp_get_thread_num(),i);
}
fprintf(stderr,"%d: leaving function2\n", omp_get_thread_num());
}
int main()
{
#pragma omp parallel
{
#pragma omp single
{
fprintf(stderr,"Executing with %d threads\n",
omp_get_num_threads());
#pragma omp task
{
function1();
}
#pragma omp task
{
function2();
}
}
}
}
这是在四个线程上执行,当然其他交错也是可能的。
OMP_NUM_THREADS=4 ./a.out
Executing with 4 threads
3: entering function2
2: entering function1
0: starting iteration 0
1: starting iteration 1
3: starting iteration 9
1: finishing iteration 1
3: finishing iteration 9
0: finishing iteration 0
3: starting iteration 8
1: starting iteration 2
2: leaving function1
0: starting iteration 3
2: starting iteration 4
3: finishing iteration 8
1: finishing iteration 2
3: starting iteration 7
0: finishing iteration 3
0: starting iteration 6
2: finishing iteration 4
1: starting iteration 5
0: finishing iteration 6
3: finishing iteration 7
1: finishing iteration 5
3: leaving function2
您可以看到只有一个线程执行每个函数[12],并且循环迭代在所有线程中共享。
推荐阅读
- javascript - javascript 从 url 获取 html 内容(页面代码)
- kubernetes - 每次 Kubernetes 因资源使用而终止进程时,我如何记录?
- android - (Chromium for android studio) 如何使用 addPossiblyUnsafeJavascriptInterface?
- visual-studio - 在 url 中使用修改后的大小写更新服务引用不起作用
- hybris - Hybris:如何每小时触发一次 cronjob?
- c# - Azure 中没有“Access-Control-Allow-Origin”标头
- r - 将网站内容保存到 txt 文件中
- java - 如何使用警报触发器从应用程序向蓝牙模块发送值?
- c++11 - 如何将qt网络的pro文件转换为cmakelist
- php - 分解字符串然后创建数组