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にリンクする必要があります (つまり、デフォルトの libc アロケータの代わりに-lmtmalloc使用するリンク)。Linux および一部の OpenSolaris および FreeBSD ディストリビューションで GNU ユーザーランドで使用される は、Doug Lea の に基づく変更されたアロケータを使用します。複数のメモリ アリーナを使用して、ロックフリーに近い動作を実現します。また、スレッドごとのアリーナを使用するように構成することもでき、一部のディストリビューション (特に RHEL 6 およびその派生物) ではその機能が有効になっています。mtmallocglibcptmalloc2dlmalloc

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 スレッドで実行されている上記のバージョンは、「実行時間: 9.44 秒」かかります。

ただし、次のコードを並列化しようとすると:

   #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、並列で呼び出すと時間が遅くなります。

(characters+1*DNA_SIZE*sizeof(char))最終的には、各サブ malloc がではなく割り当てようとしていたという事実に問題があり、((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ヒットすることがあり、配列の末尾から読み取られてしまいます。(また、この関数の引数の名前としてandを使用すると、やや混乱します。)DNA_SIZEDNA_SIZE+1argv[j]argcargv

于 2012-11-12T05:52:19.187 に答える
-1

問題はここにありdna[DNA_SIZE] = '\0';ます。これまでに 26 文字 (たとえば) のメモリを割り当て、27 番目の文字にアクセスしようとしています。配列インデックスが から始まることを常に覚えておいて0ください。

于 2012-11-12T05:23:42.017 に答える