使用omp并行时的分段错误,但不是顺序的

时间:2013-04-29 18:21:40

标签: c parallel-processing openmp libgomp

我在使用#pragma omp parallel for

时遇到了麻烦

基本上我有几百个DNA序列,我想对一个名为NNLS的算法运行。

我认为并行执行会让我的速度非常快,所以我应用了#pragma运算符。

当我按顺序运行时没有问题,结果很好,但是当我使用#pragma omp parallel运行它时,我在算法中得到了一个段错误(有时在不同的点)。

#pragma omp parallel for
for(int i = 0; i < dir_count; i++ ) {

  int z = 0;
  int w = 0;
  struct dirent *directory_entry;
  char filename[256];

  directory_entry = readdir(input_directory_dh);

  if(strcmp(directory_entry->d_name, "..") == 0 || strcmp(directory_entry->d_name, ".") == 0) {
    continue;
  }

  sprintf(filename, "%s/%s", input_fasta_directory, directory_entry->d_name);

  double *count_matrix = load_count_matrix(filename, width, kmer);

  //normalize_matrix(count_matrix, 1, width)
  for(z = 0; z < width; z++) 
    count_matrix[z] = count_matrix[z] * lambda;

  // output our matricies if we are in debug mode
  printf("running NNLS on %s, %d, %d\n", filename, i, z);
  double *trained_matrix_copy = malloc(sizeof(double) * sequences * width);
  for(w = 0; w < sequences; w++) {
    for(z = 0; z < width; z++) {
      trained_matrix_copy[w*width + z] = trained_matrix[w*width + z];
    }
  } 

  double *solution = nnls(trained_matrix_copy, count_matrix, sequences, width, i);


  normalize_matrix(solution, 1, sequences);
  for(z = 0; z < sequences; z++ )  {
    solutions(i, z) = solution[z]; 
  }

  printf("finished NNLS on %s\n", filename);

  free(solution);
  free(trained_matrix_copy);
}

gdb总是在我的帖子中以不同的品脱退出,所以我无法弄清楚出了什么问题。

我尝试过:

  • 分配每个矩阵的副本,以便它们不会在彼此之上书写
  • 使用#pragma piece
  • 的私有/共享运算符的混合
  • 使用不同的输入序列
  • 在调用NNLS之前写出我的trained_matrix和count_matrix,确保它们看起来不错。 (他们这样做!)

我有点想法。有没有人有一些建议?

4 个答案:

答案 0 :(得分:3)

解决方案:确保多线程时不使用函数中的静态变量(该死的f2c转换器)

答案 1 :(得分:1)

定义“#pragma omp parallel for”不会给你你想要的东西。根据您所拥有的算法,您必须有一个可靠的计划来确定哪些变量将被共享以及哪些变量将在处理器之间变为私有。

查看此link可以让您快速了解如何在线程之间正确地共享工作。

基于你的陈述“我在算法中得到了一个段错误(有时在不同的点)”,我认为线程之间存在竞争条件或变量初始化不正确。

答案 2 :(得分:1)

函数readdir不是线程安全的。引用readdir(3)的Linux手册页:

The data returned by readdir() may be overwritten by subsequent  calls  to  readdir()
for the same directory stream.

考虑将readdir的调用放在一个关键部分。在离开临界区之前,将从readdir()返回的文件名复制到本地临时变量,因为进入临界区的下一个线程可能会覆盖它。

还要考虑使用关键部分保护输出操作,否则不同线程的输出可能混杂在一起。

答案 3 :(得分:0)

一个非常可能的原因是堆栈限制。正如MutantTurkey所述,如果您有很多静态变量(例如子例程中定义的巨大数组),则它们可能会耗尽您的堆栈。

要解决此问题,请首先运行ulimit -s以检查该进程的堆栈限制。您可以使用ulimit -s unlimited将其设置为无限制。然后,如果仍然崩溃,请尝试通过将OMP_STACKSIZE环境变量设置为一个巨大的值(例如100MB)来增加OPENMP的堆栈。

英特尔在https://software.intel.com/en-us/articles/determining-root-cause-of-sigsegv-or-sigbus-errors进行了讨论。它具有有关堆栈和堆内存的更多信息。