1

以下のコードの 8 行目でセグメンテーション違反が発生しています。

typedef struct _my_struct {
     int pArr[21];      
     int arr1[8191];
     int arr2[8191];
     int m;
     int cLen;
     int gArr[53];  
     int dArr[8191]; 
     int data[4096];
     int rArr[53]; 
     int eArr[1024];

};

void *populate_data(void *arg) {
1   register int mask =1, iG;
2   struct _my_struct *var ;
3   var = arg;                         // arg is passed as initialized struct variable while creating thread
4   var->m = 13;
5   var->arr2[var->m] = 0;
6   for (iG = 0; iG < var->m; iG++) {
7       var->arr2[iG] = mask;
8       var->arr1[var->arr2[iG]] = iG;
9       if (var->pArr[iG] != 0)         // pArr[]= 1011000000001
10          var->arr2[var->m] ^= mask;
11      mask <<= 1;
12  }
13  var->arr1[var->arr2[var->m]] = var->m;
14  mask >>= 1;
15  for (iG = var->m+ 1; iG < var->cLen; iG++) {
16      if (var->arr2[iG - 1] >= mask)
17          var->arr2[iG] = var->arr2[var->m] ^ ((var->arr2[iG- 1] ^ mask) << 1);
18      else
19          var->arr2[iG] = var->arr2[iG- 1] << 1;
20      var->arr1[var->arr2[iG]] = iG;
21  }
22  var->arr1[0] = -1;
   }

スレッド関数は次のとおりです。

void main() {
        unsigned int tid;

        struct _my_struct  *instance = NULL;
        instance = (struct _my_struct  *)malloc(sizeof(_my_struct ));

        start_thread(&tid , 119312, populate_data, instance );          
}

int 
start_thread(unsigned int *tid, int stack_size, void * (*my_function)(void *), void *arg)
{
        pthread_t ptid = -1;
        pthread_attr_t pattrib;

        pthread_attr_init(&pattrib);

        if(stack_size > 0)
        {
            pthread_attr_setstacksize(&pattrib, stack_size);
        }
        else
        {
            pthread_attr_destroy(&pattrib);
            return -1;
        }

        pthread_create(&ptid, &pattrib, my_function, arg);      
        pthread_attr_destroy(&pattrib);

        return 0;
}

gdbでデバッグすると、このエラーが発生しました。

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffdfec80700 (LWP 22985)]
0x0000000000401034 in populate_data (arg=0x7fffffffe5d8) at Queue.c:19
19                     var->arr1[var->arr2[iG]] = iG;

そのバックトレースは次のとおりです。

#0  0x0000000000401034 in populate_data (arg=0x7fffffffe5d8) at Queue.c:159
#1  0x00007ffff7bc6971 in start_thread () from /lib/libpthread.so.0
#2  0x00007ffff792292d in clone () from /lib/libc.so.6
#3  0x0000000000000000 in ?? ()

ただし、エラーを修正することはできません。

どんな助けでも本当に感謝しています。

4

2 に答える 2

1

の呼び出しコードを表示してくださいstart_thread

スタックおよび/またはメモリ割り当てエラーである可能性が高く、構造はかなり大きく (32 ビットints を想定して 8 MB)、スタック制限をオーバーフローする可能性があります。

さらに可能性としては、範囲外になっている可能性があります。そのため、呼び出しステップを表示する必要があります。

于 2012-12-05T10:11:07.367 に答える
0

_my_structの配列の名前を変更して、それらの目的(会社の機密情報など)を非表示にしたかどうかはわかりませんが、実際に配列に名前を付けたのであれば、私はm 4年後に誰かがあなたのコードを読まなければならないとき、彼らはあなたの初期化ループをたどり、何が起こっているのかを理解するという希望を持っているというあなたに意味のある名前を付けることを提案します。ループ変数についても同じことが言えますiG

私の次のコメント/質問は、なぜメインスレッドのスタックにあるこの構造を初期化するためにスレッドを起動するのですか?初期化された後、どのスレッドがこの構造を使用しますか?それとも、それを使用する他のスレッドを作成する予定ですか?初期化スレッドがデータの初期化を完了するまで、他のスレッドがデータの使用を開始しないようにするメカニズム(ミューテックス?セマフォ?)はありますか?どちらが疑問を投げかけるのか、そもそもなぜそれを初期化するために別のスレッドを起動するのに苦労しているのか。main()から直接populate_data()を呼び出すことで初期化でき、初期化が完了するまで他のスレッドを起動することさえないため、同期について心配する必要はありません。マルチコアマシンで実行している場合は、main()が実行されている間に初期化を実行し、他の処理を実行するために別のスレッドを起動することで、多少のメリットが得られる場合がありますが、構造体のサイズ(小さくはありませんが、大きくはありません)からは、そのメリットは次のようになります。非常に小さい。また、シングルコアで実行している場合、同時実行のメリットはまったくありません。コンテキスト切り替えのオーバーヘッドが原因で、別のスレッドを起動するために時間を無駄にするだけです。ユニコア環境では、main()から直接populate_data()を呼び出す方がよいでしょう。同時実行のメリットはまったくありません。コンテキスト切り替えのオーバーヘッドが原因で、別のスレッドを起動するために時間を無駄にするだけです。ユニコア環境では、main()から直接populate_data()を呼び出す方がよいでしょう。同時実行のメリットはまったくありません。コンテキスト切り替えのオーバーヘッドが原因で、別のスレッドを起動するために時間を無駄にするだけです。ユニコア環境では、main()から直接populate_data()を呼び出す方がよいでしょう。

次のコメントは、あなたの_my_structは巨大ではないので、それ自体でスタックを爆破することはないということです。しかし、それも小さくはありません。アプリが常にこの構造体のコピーを1つだけ必要とする場合は、スタックスペースを消費しないように、グローバル変数またはファイルスコープ変数にする必要があります。

最後に、実際のバグに............

わざわざ不可解なループコードを解読しようとはしませんでしたが、valgrindは、初期化されていない場所に依存するいくつかの条件があると言っています。

~/test/so$ valgrind a.out
==27663== Memcheck, a memory error detector
==27663== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==27663== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==27663== Command: a.out
==27663==
==27663== Thread 2:
==27663== Conditional jump or move depends on uninitialised value(s)
==27663==    at 0x8048577: populate_data (so2.c:34)
==27663==    by 0x593851: start_thread (in /lib/libpthread-2.5.so)
==27663==    by 0x4BDA8D: clone (in /lib/libc-2.5.so)
==27663==
==27663== Conditional jump or move depends on uninitialised value(s)
==27663==    at 0x804868A: populate_data (so2.c:40)
==27663==    by 0x593851: start_thread (in /lib/libpthread-2.5.so)
==27663==    by 0x4BDA8D: clone (in /lib/libc-2.5.so)

私のso2.cの34行目は、上記のコード投稿の9行目に対応しています。私のso2.cの40行目は、上記のコード投稿の15行目に対応しています。

Populate_data()の先頭に以下を追加すると、これらのvalgrindエラーは消えます。

memset(arg,0,sizeof(_my_struct_t));

(構造体の定義を次のように変更しました:)

typedef struct _my_struct { int pArr[21]; ......... } _my_struct_t;

memset()呼び出しを追加するとエラーが消えるからといって、必ずしもループロジックが正しいことを意味するわけではなく、これらの場所がvalgrindによって「初期化」されたと見なされることを意味します。初期化ループの開始時にこれらの場所にすべてゼロがあることがロジックに必要な場合は、それで修正されるはずです。しかし、それが本当に適切な解決策であることを自分で確認する必要があります。

ところで...誰かがcalloc()を使用して(ダーティスタックスペースを使用するのではなく)ゼロ化された割り当てを取得することを提案しました...それも機能しますが、populate_data()を絶対確実にしたい場合は、メモリをゼロにします呼び出し元ではなく、その中で、(初期化ロジックがそのまま好きであると仮定して)、populate_data()はゼロ化されることに依存するものなので、main()はそれがゼロであるかどうかを気にする必要はありません。どちらにしても大したことではありません。

于 2012-12-05T15:35:09.353 に答える