【问题标题】:Recursive task creation results in segmentation fault in OpenMP递归任务创建导致 OpenMP 中的分段错误
【发布时间】:2020-03-03 20:55:22
【问题描述】:

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

这是我的实现:

#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

【问题讨论】:

  • 全局变量通常会出现问题,尤其是递归函数和/或线程/并行性。两者结合——哎哟!我不知道 OMP,所以也许我根本不应该发表评论,但在我看来,如果共享状态过多,您会遇到各种问题。

标签: c parallel-processing openmp multitasking


【解决方案1】:

解决方案

存在分段错误,因为您使用了private(col)。因此,col 不会从您的函数中复制,甚至不会被初始化。使用firstprivate(col) 制作col 的正确副本。

建议

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

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

【讨论】:

  • 嘿,谢谢你的建议,但我试过你的说法,但没有奏效。现在,它返回所有执行中都不存在解决方案。
  • 嘿,老兄帮帮我,我的性能大幅下降。我预计当然会有所放缓,但不会慢 10 倍。
猜你喜欢
  • 1970-01-01
  • 2022-12-25
  • 1970-01-01
  • 2021-08-15
  • 1970-01-01
  • 2014-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多