3

访问 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;
}

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

感谢所有的帮助。

4

2 回答 2

2

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

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

线程安全malloc()free()在某些libc实现中携带由内部锁定引起的高同步开销。存在用于多线程应用程序的更快的分配器。例如,在 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_SIZEor DNA_SIZE+1,从而导致读取argv[j]超出数组末尾。(此外,在此函数中使用argcandargv作为参数的名称有点令人困惑。)

于 2012-11-12T05:52:19.187 回答
-1

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

于 2012-11-12T05:23:42.017 回答