我在使用OpenMP for C ++编写例程时遇到问题。例程的代码如下:
int sudokuSolution [9][9];
bool solvep(int s[9][9], int row, int col) {
bool solution = false;
#pragma omp parallel for
for (int val = 1; val < 10; val++) {
if (isPossible(s,row,col,val)) {
s[row][col] = val;
if (solve(s, row + col / 9, (col + 1) % 9)) {
sudokuSolution[row][col] = val;
solution = true;
}
}
}
return solution;
}
在没有parallel子句的情况下运行此例程时,一切正常(即每次调用时例程返回true
)。但是,当我使用parallel时,它有时会返回false
。我无法弄清楚,为什么会发生这种情况,并且解决此错误的唯一方法是从我的角度来看,在解决方案设置为true
之后过早地结束整个并行块。但是,如果我正确地进行了研究,就没有办法过早地结束并行块。你能建议我另类吗?
编辑:根据要求添加最小功能示例:
#include <omp.h>
#include <iostream>
#include <list>
#include <chrono>
using namespace std;
bool solutionFound = false;
int sudoku [9][9] = { 5,7,0,9,0,0,0,0,8,
0,0,0,0,0,5,0,3,9,
0,0,0,0,0,0,2,0,4,
0,0,0,0,9,0,6,8,0,
0,0,0,8,0,2,0,0,0,
0,5,2,0,7,0,0,0,0,
6,0,5,0,0,0,0,0,0,
7,9,0,4,0,0,0,0,0,
2,0,0,0,0,9,0,7,6};
int sudokuSolution [9][9];
bool isPossible(int s[9][9], int row, int col, int val) {
for(int i = 0; i < 9; i++) {
if (s[row][i] == val)
return false;
if (s[i][col] == val)
return false;
if (s[row / 3 * 3 + i / 3][col / 3 * 3 + i % 3] == val)
return false;
}
return true;
}
bool solve(int s[9][9], int row, int col) {
while(s[row][col] != 0) {
col = (col + 1) % 9;
row = row + col / 8;
if(row == 9)
return true;
}
for (int val = 1; val < 10; val++) {
if (isPossible(s,row,col,val)){
sudokuSolution[row][col] = val;
s[row][col] = val;
if (solve(s, row + col / 9, (col + 1) % 9))
return true;
sudokuSolution[row][col] = 0;
s[row][col] = 0;
}
}
return false;
}
bool solvep(int sa[9][9], int row, int col) {
int s [9][9];
for(int i = 0; i < 9; i++)
for(int j = 0; j < 9; j++)
s[i][j] = sa[i][j];
while(s[row][col] != 0) {
col = (col + 1) % 9;
row = row + col / 8;
if(row == 9)
return true;
}
bool solution = false;
#pragma omp parallel for
for (int val = 1; val < 10; val++) {
if(!solutionFound) {
if (isPossible(s,row,col,val)){
s[row][col] = val;
if (solve(s, row + col / 9, (col + 1) % 9)) {
sudokuSolution[row][col] = val;
solutionFound = true;
solution = true;
}
}
}
}
return solution;
}
int main() {
for (int k = 0; k < 100; k++) {
for(int i = 0; i < 9; i++)
for(int j = 0; j < 9; j++)
sudokuSolution[i][j] = sudoku[i][j];
solutionFound = false;
solvep(sudokuSolution,0,0);
bool calcResult = solvep(sudoku,0,0);
cout << calcResult;
}
return 0;
}
答案 0 :(得分:1)
您的代码中有许多竞争条件,包括循环本身和solve
函数。在并行执行的代码中,您不得写入共享数据(s
,solution
,sudokuSolution
),尤其是全局变量(solutionFound
)。你将不得不回到你的学习材料,赶上数据竞赛和防范它们的方法。
凭借一些经验,很容易发现循环本身的问题。在被调用的函数中发现它要困难得多 - 这就是为什么在你的问题中提供一个完整的例子非常重要的原因。尝试定义您的接口,以便可变,不将任何共享数据传递给函数。从概念上讲,你必须拥有每个线程的电路板副本才能并行执行回溯。
一旦解决了写入电路板的问题,就可以使用原子写入,关键区域或减少来分享&#34;分享&#34;解决方案。但您必须同时考虑sudokuSolution[row][col]
和solution
。从逻辑上讲,我认为sudokuSolution[row][col] != 0 == solution
。
答案 1 :(得分:0)
您可以reduce使用||
运算符的所有线程上的解决方案值:
int sudokuSolution [9][9];
bool solvep(int s[9][9], int row, int col) {
bool solution = false;
#pragma omp parallel for reduction(||:solution)
for (int val = 1; val < 10; val++) {
if (isPossible(s,row,col,val)) {
s[row][col] = val;
if (solve(s, row + col / 9, (col + 1) % 9)) {
sudokuSolution[row][col] = val;
solution = true;
} else {
solution = false;
}
} else {
solution = false;
}
}
return solution;
}