2016-04-12 12 views
-3

コードのデッドロックを防ぐ方法を教えてください。デッドロックを取り除くためにコードを修正する必要がありますか? また、私はLinuxで私はセグメンテーションフォールト(コアダンプ)を持って実行するとき。デッドロックを防ぐ

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

int cnt; 
int *bites; 
int *old_bites; 
sem_t *sticks; 

void *roger(void *arg) { 
    int rog = *(int*)arg; 

    for(;;) { 
     sem_wait(&(sticks[rog]));    // left 
     sem_wait(&(sticks[(rog + 1) % cnt])); // right 

     bites[rog]++; 

     sem_post(&(sticks[(rog + 1) % cnt])); // right 
     sem_post(&(sticks[rog]));    // left 
} 

pthread_exit(NULL); 

return NULL; 
} 

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

int i; 
pthread_t *rogers; 
int *pos; 
cnt = (int)strtol(argv[1], NULL, 10); 

rogers = (pthread_t *)calloc(cnt, sizeof(pthread_t)); 
pos = (int *)malloc(cnt * sizeof(int)); 
bites = (int *)calloc(cnt, sizeof(int)); 
old_bites = (int *)calloc(cnt, sizeof(int)); 
sticks = (sem_t *)calloc(cnt, sizeof(sem_t)); 

for(i = 0; i < cnt; i++) { 
    sem_init(&(sticks[i]), 0, 1); 
} 

for(i = 0; i < cnt; i++) { 
    pos[i] = i; 
    pthread_create(&(rogers[i]), NULL, roger, (void *)&pos[i]); 
} 

for(;;) { 
    bool dead = true; 
    usleep(50000); 
    for(i = 0; i < cnt; i++) { 
     if(bites[i] != old_bites[i]) { 
      dead = false; 
     } 
    } 
    if(dead) { 
     exit(EXIT_SUCCESS); 
    } 

    for(i = 0; i < cnt; i++) { 
     printf("%8X", bites[i]); 
    } 
    printf("\n"); 
    for(i = 0; i < cnt; i++) { 
     old_bites[i] = bites[i]; 
    } 
} 

for(i = 0; i < cnt; i++) { 
    pthread_join(rogers[i], NULL); 
} 

for(i = 0; i < cnt; i++) { 
    sem_destroy(&(sticks[i])); 
} 

exit(EXIT_SUCCESS); 
} 
+3

SegFaultとデッドロック?たぶんレコードを取得し、ゼロ除算を追加しますか? –

+0

いいえ、私は噛むでしょう。あなたのアプリをデバッグするためにこれまでに行ってきたことを教えてください。どの線がセグメンテーションを上げるか? –

+0

https://en.wikipedia.org/wiki/Dining_philosophers_problem#Solutions – user3386109

答えて

0

はいこれはデッドロックになると思います。私はあなたがcntのために使っているものはわかりませんが、それは1のふりをしましょう。この場合、1つのスレッドしか作成されません。このスレッドはsem_wait(&(sticks[0]));です。次の行ではsem_wait(&(sticks[(0+1) % 1 == 0]));になります。あなたのセマフォの初期値は1であるので、最初にsem_postがなければ同じセマフォを2回待つことはできません。したがって、このスレッドは、sem_wait ingであるため、到達できないsem_postを永久に待機します。

ここで、cnt > 1(これを簡単にするためにcnt == 2としましょう)というケースを考えてみましょう。これにより、thread0とthread1が引数として渡され、0と1が関数に渡されます。このような状況が起こる可能性:あなたは、各スレッドの待機を持っている今sem_wait(&(sticks[(0+1) % 2 == 1])); // this blocks because thread1 has already sem_wait'ed this semaphore to 0

を実行thread0:sem_wait(&(sticks[(1+1) % 2 == 0])); // this blocks because thread0 has already sem_wait'ed this semaphore to 0

  • コンテキストスイッチを実行スレッド1 sem_wait(&(sticks[1]));
  • 実行スレッド1:

    • Thread0がsem_wait(&(sticks[0]));
    • コンテキストスイッチを実行します===>デッドロックを続行する前に、他のものからsem_postを取得してください。デッドロックの原因となる状況はさらに複雑になりますが、このシナリオでは値を増やすために、cntの規模になると思います。

      1つのリソースを保護するために2つのセマフォを使用しているのはなぜですか?この理論は私に間違って聞こえる。あなたはそのアプローチであなたのアトミック性を失います(私が間違っていれば私を修正してください)。

      さらに、bitesアレイの競合状態があります。メインスレッドは、同期を読み取る前に同期を監視していません。これはsegフォルトに関連している可能性があります。

  • +0

    私はsegFaultを固定しているので、デッドロックプログラムは終了しませんか?出力を継続的に出力しますか? – littlerain

    +0

    @littlerain提供されているコードから、ワーカースレッドが最終的にデッドロックすることが予想されます。すべての印刷はメインループで行われ、無限のforループに入り、 'dead'がtrueになると終了します。これは時々起こるかもしれませんが、そうでないかもしれません。 'pthread_join'と' sem_destroy'ループには決して行きません。セマフォの配列は論理的なエラーだと思います。あなたは1つしか持っていないはずです。このように複数のセマフォを使用して単一のリソース( 'bites'配列)を保護することで、スレッドの同期化に基づくアトミック性が取り除かれます。 – yano