2016-03-19 22 views
0

pthread_joinを使用してデッドロックを示す簡単な例を探しています。しかし、これは自明ではありません。pthread_joinデッドロックの簡単な例

私はこれを開始しました:

void* joinit(void* tid) 
{ 
    pthread_t* tid_c = (pthread_t*)tid; 
    int retval = pthread_join(*tid_c, NULL); 
    printf("In joinit: tid = %d, retval = %d \n", *tid_c, retval); 
    return NULL; 
} 

int main() 
{ 
    pthread_t thread1; 
    pthread_t thread2; 

    pthread_create(&thread1, NULL, joinit, &thread2); 
    pthread_create(&thread2, NULL, joinit, &thread1); 

    pthread_join(thread2, NULL); 

    return 0; 
} 

しかしthread1ためpthread_createが呼び出されたときthread2がまだ指定されていないので、しかし、それはEINVAL '(不正な引数)と言います。

アイデア?

+0

私はこれを試してみました、それが働いていたが、問題は時々、私は再びEIVALを取得するので、それが唯一のSOMETIMES作品です。 私はメソッドjoinitでerrnoをチェックしています! –

+0

はい、スレッドが開始された時点を決定することはできませんが、OSはそれを行います。 –

+0

はい、わかっています。私は信頼できるデッドロック状況が必要です。 –

答えて

2

あなただけpthread_joinは、次のコードに似た何かをすることができ、デッドロックを引き起こす可能性があることを証明したいとしている場合:

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

void* joinit(void* tid) 
{ 
    printf("In %#x, waiting on %#x\n", pthread_self(), (*((pthread_t*)tid))); 
    pthread_join((*((pthread_t*)tid)), NULL); 
    printf("Leaving %#x\n", pthread_self()); 
    return NULL; 
} 

int main(void) 
{ 
    pthread_t thread1 = pthread_self(); 
    pthread_t thread2; 
    pthread_create(&thread2, NULL, joinit, &thread1); 
    joinit(&thread2); 
    return 0; 
} 

これは、生成されたスレッド上で待機するようにメインスレッドの原因となりますし、あなたが実証しようとしているものを混乱させる余分なロックプリミティブを必要とせずに、メインスレッド上で待機する(生成されたデッドロックを保証する)生成されたスレッド。

そして、もっと直接ご質問のいくつかに答えるために:

thread1ためpthread_createが呼び出されたときthread2がまだ指定されていないので、それはEINVAL '(不正な引数)と言います。

...とコメントの一つから...

私はこれを試してみました、それが働いていたが、問題は、ある時々私は再びEINVALを取得するので、それが唯一のSOMETIMES動作します。あなたのコードで

、あなたは2つのスレッド産卵する連続pthread_createを呼び出す:あなたは上で参加することで渡されたスレッドハンドルをつかみ、あなたのjoinitコードで

pthread_create(&thread1, NULL, joinit, &thread2); 
pthread_create(&thread2, NULL, joinit, &thread1); 

を:

pthread_t* tid_c = (pthread_t*)tid; 
int retval = pthread_join(*tid_c, NULL); 

このの場合はとなり、それ以外の場合はEINVALとなり、理由はそれぞれtime slicesとなります文脈とsequencing。最初のpthread_createが呼び出されたときにはthread1への有効なハンドルが返されますが、少なくともthread2へのハンドルは有効ではありません。少なくとも2番目のpthread_createが呼び出されるまで有効ではありません。

これは、スレッドが作成されると、返されたスレッドハンドルが有効であるにもかかわらず、スレッドが実際に動作していることを意味します。このような場合、1つのスレッドが「予想される」より多くのコードを実行する可能性があります。あなたのコードでは、両方のpthread_create機能それぞれが有効なハンドルを指すようにtid_cを可能pthread_join文を打つ前に、スレッドの十分な「時間」を生み出し与えることができるメインスレッドに割り当てられたタイムスライスに呼び出されたことが起こるかもしれません。 EINVALの場合、pthread_create(&thread1, NULL, joinit, &thread2)が呼び出され、pthread_create(&thread2, NULL, joinit, &thread1)が有効なハンドル(エラーを引き起こす)を与える前に、生成されたスレッドはpthread_join(*tid_c, NULL)に達しました。

あなたが今どのように似たコードを維持したい場合は、スレッドが途中で何かを終了するか、呼び出していないことを確認するために、ある種のロックを追加する必要があります。

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

static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 

void* joinit(void* tid) 
{ 
    /* this can be above the lock because it will be valid after lock is acquired */ 
    pthread_t* tid_c = (pthread_t*)tid; 
    int retval = -1; 
    pthread_mutex_lock(&lock); 
    pthread_mutex_unlock(&lock); 
    printf("%#x waiting on %#x\n", pthread_self(), *tid_c); 
    retval = pthread_join(*tid_c, NULL); 
    printf("In joinit: tid = %d, retval = %d \n", *tid_c, retval); 
    return NULL; 
} 

int main() 
{ 
    pthread_t thread1; 
    pthread_t thread2; 
    /* get the lock in the main thread FIRST */ 
    pthread_mutex_lock(&lock); 
    pthread_create(&thread1, NULL, joinit, &thread2); 
    pthread_create(&thread2, NULL, joinit, &thread1); 
    /* by this point, both handles are "joinable", so unlock */ 
    pthread_mutex_unlock(&lock); 

    /* can wait on either thread, but must wait on one so main thread doesn't exit */ 
    pthread_join(thread2, NULL); 
    return 0; 
} 

・ホープ、この助けられる。

+0

デッドロックが発生した場合、あなたのコードだけでOPを認識させることはできません。そのためにpthread_joinの戻り値をチェックする必要があります。この場合、pthread_joinは35(EDEADLK)を返し、スレッドのいずれか1つだけを返します。 'int ret = pthread_join((*((pthread_t *)tid))、NULL); のprintf( "%D%sの\ n" は、RET、にstrerror(RET)); ' 出力:0x7fb4740で 、0x77ca700で0x77ca700 を待っている、0x7fb4740 35リソースデッドロックが0x77ca700 0成功を残し を避ける上で待っています 0x7fb4740を返す ここでは、pthread_joinが私たちにとってデッドロックを処理し、待機部分をスキップしました。 – kalimba

+0

@kalimba ..実際に私のコードを実行していると、WindowsやOpenBSDのようないくつかのシステムでデッドロックが発生します。他のものは、デッドロック状態が発生したことを示す値(例えば、カーネル設定)を返すこともあります。私のSlackwareシステムでは、 'EDEADLK'は' 35'ではなく '22'と定義されています。POSIXは標準的なものではないので、 'pthread_join'の戻り値をチェックすることが重要ですが、デッドロックが何であるかを理解し、最初に避けることが重要です(OPが1つを示そうとしていて、そのような場合はまず避けてください)。 – txtechhelp

+0

あなたの応答を感謝:)私の情報はposixに限られていた。 – kalimba

0

pthread_joinへのコールがmainにあるため、それぞれが同じスレッドを終了するのを待っている2つのスレッドがエラーの主な理由です。もう1つの問題は、各スレッドが別のスレッドのIDを正しく認識しないことです。

はこのようにそれを修正:

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

pthread_t thread1; 
pthread_t thread2; 
pthread_mutex_t mutex; 
pthread_cond_t cond; 
int go = 0; 


void* joinit(void* ptr) 
{ 
    // wait until both thread IDs are known 
    pthread_mutex_lock(&mutex); 
    while (go == 0) 
     pthread_cond_wait(&cond, &mutex); 
    pthread_mutex_unlock(&mutex); 

    pthread_t* tid_c = *((pthread_t**) ptr); 
    printf("About to wait\n"); 
    int retval = pthread_join(*tid_c, NULL); 
    printf("In joinit: tid = %d, retval = %d \n", *tid_c, retval); 

    // tell the other threads we're done 
    pthread_mutex_lock(&mutex); 
    go++; 
    pthread_cond_broadcast(&cond); 
    pthread_mutex_unlock(&mutex); 

    return NULL; 
} 

int main() 
{ 
    // setup synchronization 
    pthread_mutex_init(&mutex, NULL); 
    pthread_cond_init(&cond, NULL); 

    pthread_create(&thread1, NULL, joinit, &thread2); 
    pthread_create(&thread2, NULL, joinit, &thread1); 

    // tell the threads to go 
    pthread_mutex_lock(&mutex); 
    go = 1; 
    pthread_cond_broadcast(&cond); 
    pthread_mutex_unlock(&mutex); 

    // wait for both threads to finish 
    pthread_mutex_lock(&mutex); 
    while (go != 3) 
     pthread_cond_wait(&cond, &mutex); 
    pthread_mutex_unlock(&mutex); 

    return 0; 
}