c++ - 如何在 OpenMP 中为 if-else、increment 的任意数量的线程获得相同的并行输出?
问题描述
我想在没有任何原子操作或关键部分的情况下并行化以下代码。
我的代码在下面给出,我已经尝试过但结果不是预期的。对于任意数量的线程,我想要相同的输出,其中输出顺序可能不同,即使用 1 个线程的第 5 行可能出现在第 8 行,而使用 4 个线程。如果我没记错的话,这里的临界区是 k++ 区域。请建议我如何在 OpenMP 中做到这一点而不使用关键/原子类子句。
#include <iostream>
#include <vector>
#include "omp.h"
#include "cstdlib"
using namespace std;
int main(int argc, char *argv[]){
int t = atoi(argv[1]);
vector<int> A{0,3,5,7};
vector<int> B{1,2,3,0,3,0,3,0,1,2};
int k = 0, j;
for(int i = 0; i<A.size(); i++){
k = A[i];
#pragma omp parallel for schedule(static) num_threads(t)
for(j = 0; j < A.size(); j++){
if(j == B[k]){
printf("i(yes):%d # B[%d] = %d, thread = %d\n",i, k, B[k], omp_get_thread_num());
if(k < B.size() && k < A[i+1]){
k++;
}
}else{
printf("i(no):%d # j = %d, k = %d, thread = %d\n",i, j, k, omp_get_thread_num());
}
}
}
return 0;
}
`
当我使用 1 个线程运行时,我得到以下输出:
$ ./a.out 1
i(no):0 # j = 0, k = 0, thread = 0
i(yes):0 # B[0] = 1, thread = 0
i(yes):0 # B[1] = 2, thread = 0
i(yes):0 # B[2] = 3, thread = 0
i(yes):1 # B[3] = 0, thread = 0
i(no):1 # j = 1, k = 4, thread = 0
i(no):1 # j = 2, k = 4, thread = 0
i(yes):1 # B[4] = 3, thread = 0
i(yes):2 # B[5] = 0, thread = 0
i(no):2 # j = 1, k = 6, thread = 0
i(no):2 # j = 2, k = 6, thread = 0
i(yes):2 # B[6] = 3, thread = 0
i(yes):3 # B[7] = 0, thread = 0
i(no):3 # j = 1, k = 7, thread = 0
i(no):3 # j = 2, k = 7, thread = 0
i(no):3 # j = 3, k = 7, thread = 0
但是当我使用 2 个线程运行时,我得到了以下不同步和预期的输出。
$ ./a.out 2
i(no):0 # j = 0, k = 0, thread = 0
i(yes):0 # B[0] = 1, thread = 0
i(no):0 # j = 2, k = 0, thread = 1
i(no):0 # j = 3, k = 1, thread = 1
i(no):1 # j = 2, k = 3, thread = 1
i(no):1 # j = 3, k = 3, thread = 1
i(yes):1 # B[3] = 0, thread = 0
i(no):1 # j = 1, k = 4, thread = 0
i(no):2 # j = 2, k = 5, thread = 1
i(no):2 # j = 3, k = 5, thread = 1
i(yes):2 # B[5] = 0, thread = 0
i(no):2 # j = 1, k = 6, thread = 0
i(yes):3 # B[7] = 0, thread = 0
i(no):3 # j = 2, k = 7, thread = 1
i(no):3 # j = 3, k = 7, thread = 1
i(no):3 # j = 1, k = 7, thread = 0
解决方案
无论有没有原子,你都不能并行化你的循环。由于k
in 迭代的值j + 1
取决于迭代中发生的事情j
,因此迭代必须按顺序运行。(问问自己,j
如果j
== 1 迭代还没有增加,那么 == 2 的迭代如何才能正常运行k
?)
您当前的代码在 上存在竞争k
,当它被另一个线程更新时,它的值可能会在迭代中间发生变化。
推荐阅读
- hibernate - "No session currently bound to execution context" in unit test with DropWizard Hibernate
- python - 每当我尝试在 Python 中读取文件时都会出现错误,我该如何解决这个问题?
- ansible - 使用列表在 Ansible 中配置 Grafana 数据源
- rust - 为什么将函数移动到结构上的方法时,#[inline] 属性会停止工作?
- javascript - 使用 FastAPI 和 JS fetch 上传 .csv
- r - 有没有办法在生成随机 igraph 网络时允许平行边?
- android - Android/Kotlin:使用 URLConnection 发送数据时出现问题
- javascript - 为什么 Stats.min.js 只能通过 `script src=` 导入,而不能通过 `import` 导入?
- javascript - 在输入中的每 3 个数字后添加空格
- mysql - SQL QUERY - 合并表