我在使用#pragma omp parallel
时有问题基本上我有几百个DNA序列,我想用一种叫做NNLS的算法来运行。
我认为并行处理可以提高速度,所以我使用了#pragma操作符。
当我按顺序运行它时,没有问题,结果很好,但是当我用#pragma omp parallel for运行它时,我在算法中得到一个段错误(有时在不同的点上)。
#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, %dn", 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 %sn", filename);
free(solution);
free(trained_matrix_copy);
}
gdb总是在我的线程中以不同的品脱退出,所以我不知道出了什么问题。
我已经试过了:
- 分配每个矩阵的副本,这样它们就不会在彼此的顶部写入
- 对#pragma片段 使用私有/共享操作符的混合
- 使用不同的输入序列
- 在调用NNLS之前写出我的trained_matrix和count_matrix,确保它们看起来正常。(他们)
我有点没主意了。有人有什么建议吗?
解决方案:确保在多线程(该死的f2c转换器)时不要在函数中使用静态变量
定义"#pragma omp parallel for"不会给你想要的。根据你的算法,你必须有一个可靠的计划,哪些变量将在处理器之间共享,哪些变量将在处理器之间私有。
查看这个链接应该会让您快速了解如何在线程之间正确地共享工作。
根据你的声明"我在算法中得到一个段错误(有时在不同的点)",我认为线程之间存在竞争条件或变量初始化不当。
readdir函数不是线程安全的。引用readdir(3)的Linux手册页:
The data returned by readdir() may be overwritten by subsequent calls to readdir()
for the same directory stream.
考虑将对readdir的调用放在临界区中。在离开临界区之前,将readdir()返回的文件名复制到一个本地临时变量,因为下一个进入临界区的线程可能会覆盖它。
也要考虑用临界区保护你的输出操作,否则来自不同线程的输出可能会混杂在一起。
一个很可能的原因是堆栈限制。正如MutantTurkey所提到的,如果你有很多静态变量(比如在子例程中定义的一个巨大的数组),它们可能会耗尽你的堆栈。
要解决这个问题,首先运行ulimit -s
来检查进程的堆栈限制。您可以使用ulimit -s unlimited
将其设置为无限制。然后,如果它仍然崩溃,尝试通过将OMP_STACKSIZE
环境变量设置为一个很大的值来增加OPENMP的堆栈,如100MB
。
英特尔在https://software.intel.com/en-us/articles/determining-root-cause-of-sigsegv-or-sigbus-errors上进行了讨论。