2016-08-01 3 views
0

5スレッドを作成し、それぞれが長さ10の配列のsize-2チャンクで作業するようにCプログラムをデバッグするのに問題があります。目標はその配列の合計を得ることです。私の実際のプログラムは、ダイナミックな配列サイズとスレッド数を必要とするので、これより少し些細なことですが、私はこの簡単な問題に単純化しようとしましたが、それでも動作しません。Cでは、ループで初期化されたpthreadは、mutexにもかかわらず割り当て関数を正しく実行しません。

すなわち、

アレイ= {1 2 3 4 5 6 7 8 9 10}

次いで、アレイ上で動作するスレッド1 [0]、配列[1]

とスレッド2に働きますアレイ[2]及び配列[3]

等...アレイ上で動作thread5

[8]及び配列[9]

しかし、コードを実行すると、ミューテックスロックを使用していても奇妙な結果が得られます。

たとえば、このプログラムを実行すると、これは私の結果の1つです。

Thread #1 adding 3 to 0 New sum: 3 
Thread #1 adding 4 to 3 New sum: 7 
Thread #2 adding 5 to 7 New sum: 12 
Thread #2 adding 6 to 12  New sum: 18 
Thread #3 adding 7 to 18  New sum: 25 
Thread #3 adding 8 to 25  New sum: 33 
Thread #4 adding 9 to 33  New sum: 42 
Thread #4 adding 9 to 42  New sum: 51 
Thread #4 adding 10 to 51  New sum: 61 
Thread #4 adding 10 to 61  New sum: 71 
Sum: 71 

まず、最初の3行の「新しい合計」の前にタブがないのはなぜですか? (calculate_sum関数のmy printfログを参照してください)。さらに重要なのは、なぜthread0がそのジョブを実行しないのか、なぜスレッド4が2回実行されるのかです。

#include <stdio.h> 
#include <stdlib.h> 
#include <pthread.h> 

typedef struct { 
    int start, end, thread_number; 
    int *data; 
} Func_args; 

static pthread_mutex_t mutex; 
static int sum = 0; 

void *calculate_sum(void *args) { 

    int *arr = ((Func_args *)args)->data; 
    int i = ((Func_args *)args)->start; 
    int end = ((Func_args *)args)->end; 
    int t_id = ((Func_args *)args)->thread_number; 

    while (i < end) { 
     pthread_mutex_lock(&mutex); 
     printf("Thread #%d adding %d to %d\t", t_id, arr[i], sum); 
     sum += arr[i++]; 
     printf("New sum: %d\n", sum); 
     pthread_mutex_unlock(&mutex); 
    } 

    return NULL; 
} 

#define NUM_THREAD 5 
#define ARRAY_LEN 10 

int main(int argc, char **argv) { 

    int array[ARRAY_LEN] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
    pthread_t tid[NUM_THREAD]; 
    int i, pos = 0; 

    pthread_mutex_init(&mutex, NULL); 

    for (i = 0; i < NUM_THREAD; i++) { 
     Func_args args; 
     args.data = array; 
     args.thread_number = i; 
     args.start = pos; 
     pos += 2; 
     args.end = pos; 
     pthread_create(&tid[i], NULL, calculate_sum, &args); 
    } 

    for (i = 0; i < NUM_THREAD; i++) 
     pthread_join(tid[i], NULL); 

    pthread_mutex_destroy(&mutex); 
    printf("Sum: %d\n", sum); 

    return 0; 
} 
+0

"なぜ最初の3行の「新しい合計」の前にタブがありませんか? - がある。 – immibis

答えて

4

スレッドが開始する前に破棄されるオブジェクトへのポインタを各スレッドに渡しています。

argsはローカルなので、プログラムがスコープを終了したとき、つまりforループ本体の最後でプログラムが破棄されます。

スレッドが起動するまで数分かかるので、スレッドがそれ以降に開始すると、破棄されたオブジェクトにアクセスします。実際には、メモリは次のスレッドの値を格納するために再利用されます。

mallocでスレッドデータを動的に割り当てることで修正できます(スレッド内でfreeに記憶されているか、pthread_createが失敗した場合)。

+0

ああそう!それは私の元々の実装でしたが、mallocの考え方が好きではなかったので、毎回フリーズしました。それは意味があります、私はそれを試みるつもりです! – vgbcell

+0

@vgbcellまた、ローカル配列を使用し、各スレッドに別の配列要素へのポインタを渡すこともできます(そして、すべてのスレッドが配列の一部で完了するまで配列が破棄されないようにしてください) – immibis

関連する問題