【问题标题】:Segmentation Fault when using OpenMP when creating an array在创建数组时使用 OpenMP 时出现分段错误
【发布时间】:2012-10-31 13:30:48
【问题描述】:

在 for 循环中访问数组时出现分段错误。 我要做的是生成 DNA 字符串的所有子序列。

当我在 for 中创建数组时发生了这种情况。看了一会,发现openmp是限制栈大小的,所以改用堆会更安全。于是我改代码使用malloc,但问题依旧。

这是完整的代码:

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>

#define DNA_SIZE 26 
#define DNA "AGTC"

static char** powerset(int argc, char* argv)
{
    unsigned int i, j, bits, i_max = 1U << argc;

    if (argc >= sizeof(i) * CHAR_BIT) {
        fprintf(stderr, "Error: set too large\n");
        exit(1);
    }
    omp_set_num_threads(2);
    char** subsequences = malloc(i_max*sizeof(char*));

    #pragma omp parallel for shared(subsequences, argv) 
    for (i = 0; i < i_max ; ++i) {
        //printf("{");
        int characters = 0;
        for (bits=i; bits ; bits>>=1)
            if (bits & 1)
                ++characters;

        //This is the line where the error is happening. 
        char *ss = malloc(characters+1 * sizeof(char)*16);//the *16 is just to save the cache lin       

        int ssindex = 0;

        for (bits = i, j=0; bits; bits >>= 1, ++j) {
            if (bits & 1) {
                //char a = argv[j];
                ss[ssindex++] = argv[j] ;
            } 
        }
        ss[ssindex] = '\0';
        subsequences[i] = ss;       
    }
    return subsequences;
}

char* getdna()
{
    int i;

    char *dna = (char *)malloc((DNA_SIZE+1) * sizeof(char));

    for(i = 0; i < DNA_SIZE; i++)
    {
        int randomDNA = rand() % 4;
        dna[i] = DNA[randomDNA];
    }

    dna[DNA_SIZE] = '\0';

    return dna;
}

void printResult(char** ss, int size)
{
    //PRINTING THE SUBSEQUENCES
    printf("SUBSEQUENCES FOUND:\r\n");
    int i;
    for(i = 0; i < size; i++)
    {
        printf("%i.\t{ %s } \r\n",i+1 , ss[i]);
        free(ss[i]);
    }
    free(ss);
}

int main(int argc, char* argv[])
{
    srand(time(NULL));
    double starttime, stoptime;
    starttime = omp_get_wtime();
    char* a = getdna();
    printf("%s\r\n", a);
    int size = pow(2, DNA_SIZE);
    printf("number of subsequences: %i\r\n", size);

    char** subsequences = powerset(DNA_SIZE, a);    
    //todo: make it optional printing to the stdout or saving to a file
    //printResult(subsequences, size);
    stoptime = omp_get_wtime();

    printf("Tempo de execucao: %3.2f segundos\n\n", stoptime-starttime);
    printf("Numero de sequencias geradas: %i\n\n", size);
    free(a);
    return 0;
}

我还尝试使用 #pragma omp critical 使 malloc 行变得至关重要,但这没有帮助。 我也尝试使用 -mstackrealign 进行编译,但也没有用。

感谢所有帮助。

【问题讨论】:

  • 顺便说一下,OpenMP 对堆栈大小的限制可以轻松修改。见this answer

标签: arrays c multithreading parallel-processing openmp


【解决方案1】:

您应该使用更高效的线程安全内存管理。

应用程序可以在编译器生成的动态/可分配数组、矢量化内在函数等代码中显式或隐式使用malloc()free()

某些libc 实现中的线程安全malloc()free() 带有由内部锁定引起的高同步开销。存在用于多线程应用程序的更快的分配器。例如,在 Solaris 上,多线程应用程序应与“MT-hot”分配器 mtmalloc 链接(-lmtmalloc 链接以使用 mtmalloc 而不是默认的 libc 分配器)。 glibc,用于 Linux 和一些带有 GNU 用户空间的 OpenSolaris 和 FreeBSD 发行版,使用修改后的 ptmalloc2 分配器,它基于 Doug Lea 的 dlmalloc。它使用多个内存区域来实现接近无锁的行为。它还可以配置为使用每线程领域,并且某些发行版(尤其是 RHEL 6 及其衍生版本)启用了该功能。

static char** powerset(int argc, char* argv)
{
    int i, j, bits, i_max = 1U << argc;

    if (argc >= sizeof(i) * CHAR_BIT) {
        fprintf(stderr, "Error: set too large\n");
        exit(1);
    }
    omp_set_num_threads(2);
    
    
    char** subsequences = malloc(i_max*sizeof(char*));
    
    int characters = 0;
    for (i = 0; i < i_max ; ++i)
    {
         for (bits=i; bits ; bits>>=1)
            if (bits & 1)
                ++characters;
         
        subsequences[i] = malloc(characters+1 * sizeof(char)*16);
        characters = 0;
    }
    
    
    #pragma omp parallel for shared(subsequences, argv) private(j,bits)
    for (i = 0; i < i_max; ++i)
    {     

        int ssindex = 0;

        for (bits = i, j=0; bits; bits >>= 1, ++j) {
            if (bits & 1) {
                subsequences[i][ssindex++] = argv[j] ;
            } 
        }
       subsequences[i][ssindex] = '\0';
    }
    
    return subsequences;
}

我在并行区域之前创建(并分配)所需的数据,然后进行剩余的计算。在 24 核机器上运行 12 线程的上述版本采用“Tempo de execucao: 9.44 segundos”。

但是,当我尝试并行化以下代码时:

   #pragma omp parallel for shared(subsequences) private(bits,characters)
    for (i = 0; i < i_max ; ++i)
            {
                 for (bits=i; bits ; bits>>=1)
                    if (bits & 1)
                        ++characters;
                 
                subsequences[i] = malloc(characters+1 * sizeof(char)*16);
                characters = 0;
            }

需要“执行速度:10.19 秒”

如您所见,并行调用 malloc 会导致时间变慢。

最终,您可能会遇到问题,即每个 sub-malloc 都试图分配 (characters+1*DNA_SIZE*sizeof(char)) 而不是 ((characters+1)*DNA_SIZE*sizeof(char)),如果我在并行部分中不需要乘以缓存行大小的因子了解您要避免的事情。

这段代码似乎也有一些问题:

for (bits = i, j=0; bits; bits >>= 1, ++j) {
    if (bits & 1) {
        //char a = argv[j];
        ss[ssindex++] = argv[j] ;
    }
}

使用此代码,j 有时会命中DNA_SIZEDNA_SIZE+1,导致读取argv[j] 超出数组末尾。 (另外,在这个函数中使用 argcargv 作为参数的名称有点令人困惑。)

【讨论】:

    【解决方案2】:

    问题出在dna[DNA_SIZE] = '\0';。到目前为止,您已经为 26 个字符(比如说)分配了内存,并且您正在尝试访问第 27 个字符。永远记住数组索引从0开始。

    【讨论】:

    • 不这么认为; char *dna = (char *)malloc((DNA_SIZE+1) * sizeof(char));
    • 糟糕,我没注意到:(谢谢@JonathanDursi
    猜你喜欢
    • 2011-11-24
    • 2016-01-07
    • 1970-01-01
    • 1970-01-01
    • 2013-02-23
    • 1970-01-01
    • 2014-05-19
    相关资源
    最近更新 更多