过早结束OpenMP

时间:2017-11-16 17:47:38

标签: c++ openmp

我在使用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;
}

2 个答案:

答案 0 :(得分:1)

您的代码中有许多竞争条件,包括循环本身和solve函数。在并行执行的代码中,您不得写入共享数据(ssolutionsudokuSolution),尤其是全局变量(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;
}