递归任务创建导致 OpenMP 中的分段错误

Recursive task creation results in segmentation fault in OpenMP

我正在尝试使用 OpenMP 实现 nqueens 求解器,我的串行代码工作正常,但是当我尝试对其执行任务并行时,出现分段错误或空 rows/cols。

这是我的实现:

#define N 8
bool SOLUTION_EXISTS = false; // THIS IS GLOBAL

bool solve_NQueens(int board[N][N], int col) 
{ 

    if (col == N) 
    { 
        #pragma omp critical
            print_solution(board); 
        SOLUTION_EXISTS = true;
        return true; 
    } 

    for (int i = 0; i < N; i++) 
    {  
        if (can_be_placed(board, i, col) ) 
        { 
            #pragma omp taskgroup
            {   
                #pragma omp task private(col) shared(i) firstprivate(board)
                {
                    board[i][col] = 1; 
                    SOLUTION_EXISTS = solve_NQueens(board, col + 1) || SOLUTION_EXISTS; 
                    board[i][col] = 0; 
                }
            }    
        } 
    } 
    return SOLUTION_EXISTS; 
}

而这个函数的第一次调用是:

#pragma omp parallel
{
    #pragma omp single
    {
        solve_NQueens(board, 0);
    }
}

当我将 col 设为私有时,它会出现分段错误。如果我不放置任何变量范围,则会打印出模棱两可和错误的解决方案。

我正在使用 gcc 4.8.5

解决方案

因为您使用 private(col),所以出现分段错误。因此, col 不会从您的函数中复制,甚至不会初始化。使用 firstprivate(col) 复制 col.

建议

omp taskgroup 将使您的代码 运行 顺序排列,因为在作用域的末尾有一个隐式屏障。最好避免它(例如,通过在循环末尾使用 omp taskwait 并稍微更改其余代码)。 如果您想更改它,请注意必须使用 firstprivate 而不是 shared.

复制 i

此外,避免在并行代码中使用像 SOLUTION_EXISTS 这样的全局变量。这通常会导致 lot 从恶性错误到缓慢代码的问题。如果您仍然 need/want 这样做,则 多线程 中使用的变量必须 受保护 使用例如 omp atomicomp critical 指令。