5

pthread_join()アプリケーションがシャットダウンしているため、呼び出しで簡単に再現できないSEGVをC ++で取得しています(10万回のテスト実行に約1回発生します) 。errnoの値を確認しましたが、ゼロです。これはCentosv4で実行されています。

どのような条件下pthread_join()でSEGVを取得しますか?これは非常にまれであるため、ある種の競合状態である可能性があります。ある人は、pthread_detach()とpthread_exit()を呼び出すべきではないと提案していますが、その理由はわかりません。

私の最初の作業仮説は、他のスレッドで実行されpthread_join()ている間に呼び出されpthread_exit()、これが何らかの形でSEGVにつながるというものでしたが、多くの人がこれは問題ではないと述べています。

アプリケーションの終了時にメインスレッドでSEGVを取得する失敗したコードは、おおよそ次のようになります(簡潔にするためにエラーリターンコードのチェックは省略されています)。

// During application startup, this function is called to create the child thread:

return_val = pthread_create(&_threadId, &attr,
                            (void *(*)(void *))initialize,
                            (void *)this);

// Apparently this next line is the issue:
return_val = pthread_detach(_threadId);

// Later during exit the following code is executed in the main thread:

// This main thread waits for the child thread exit request to finish:

// Release condition so child thread will exit:
releaseCond(mtx(), startCond(), &startCount);

// Wait until the child thread is done exiting so we don't delete memory it is
// using while it is shutting down.
waitOnCond(mtx(), endCond(), &endCount, 0);
// The above wait completes at the point that the child thread is about
// to call pthread_exit().

// It is unspecified whether a thread that has exited but remains unjoined
// counts against {PTHREAD_THREADS_MAX}, hence we must do pthread_join() to
// avoid possibly leaking the threads we destroy.
pthread_join(_threadId, NULL); // SEGV in here!!!

releaseCond()終了時に結合されている子スレッドは、メインスレッドで呼び出される上記のポイントから始まる次のコードを実行します。

// Wait for main thread to tell us to exit:
waitOnCond(mtx(), startCond(), &startCount);

// Tell the main thread we are done so it will do pthread_join():
releaseCond(mtx(), endCond(), &endCount);
// At this point the main thread could call pthread_join() while we 
// call pthread_exit().

pthread_exit(NULL);

スレッドは正しく起動しているように見え、アプリケーションの起動時の作成中にエラーコードは生成されず、スレッドはタスクを正しく実行しました。これには、アプリケーションが終了するまでに約5秒かかりました。

このまれなSEGVが発生する原因と、それに対してどのように防御的にプログラムすることができるでしょうか。1つの主張は、pthread_detach()の呼び出しが問題であるということです。もしそうなら、コードをどのように修正する必要がありますか。

4

3 に答える 3

4

仮定:

  1. pthread_createゼロを返します(チェックしていますよね?)
  2. attr有効なpthread_attr_tオブジェクトです (どのように作成していますか?代わりに NULL を渡さないのはなぜですか?)
  3. attrスレッドを切り離して作成することを指定しません
  4. あなたはどこかのスレッドでpthread_detachまたはを呼び出しませんでしたpthread_join

...その後、失敗することは「不可能」でpthread_joinあり、ランタイムに他のメモリ破損またはバグがあります。

[アップデート]

根拠セクションは次のようにpthread_detach述べています。

*pthread_join*() または *pthread_detach*() 関数は、スレッドに関連付けられたストレージを再利用できるように、作成されるすべてのスレッドに対して最終的に呼び出す必要があります。

これらが相互に排他的であるとは言いませんが、pthread_joinドキュメントでは次のように指定されています。

*pthread_join*()のスレッド引数で指定された値が結合可能なスレッドを参照していない場合、動作は未定義です。

切り離されたスレッドは結合できないという正確な文言を見つけるのに苦労していますが、それは本当だと確信しています。

したがって、pthread_joinまたはのいずれかを呼び出しますpthread_detachが、両方を呼び出すことはできません。

于 2012-07-11T22:52:25.417 に答える
0

問題を完全に診断するには情報が不十分です。pthread_join問題は、との間の競合状態よりも、コード内の未定義の動作である可能性が高いという他の投稿された回答に同意しますpthread_exitpthreadしかし、そのような競合の存在がライブラリ実装のバグを構成することにも同意します。

についてpthread_join

return_val = pthread_create(&_threadId, &attr,
                            (void *(*)(void *))initialize,
                            (void *)this);
//...
pthread_join(_threadId, NULL); // SEGV in here!!!

結合がクラスにあるようです。mainこれにより、 が結合しようとしている間にオブジェクトが削除される可能性が生じます。pthread_joinが解放されたメモリにアクセスしている場合、結果は未定義の動作になります。解放されたメモリへのアクセスは非常に頻繁に検出されないため、私はこの可能性に傾いています。

についてpthread_exit:Linuxのmanページ、およびPOSIX仕様の状態:

pthread_exit() への暗黙的な呼び出しは、main() が最初に呼び出されたスレッド以外のスレッドが、それを作成するために使用された開始ルーチンから戻るときに行われます。関数の戻り値は、スレッドの終了ステータスとして機能します。

pthread_exit() の暗黙的または明示的な呼び出しの結果として呼び出されたキャンセル クリーンアップ ハンドラまたはデストラクタ関数から呼び出された場合、pthread_exit() の動作は未定義です。

呼び出しがクリーンアップ ハンドラーで行われると、pthread_exit未定義の動作が発生します。

于 2012-07-11T23:06:05.133 に答える
0

pthread_joinpthread_exitおよび関連ページの標準ドキュメントを読むと、結合は「ターゲット スレッドが終了するまで」実行を中断し、pthread_exit を呼び出すスレッドは pthread_exit の呼び出しが完了するまで終了しないため、心配していることはありません。問題になるな。

どこかでメモリが破損したか (Nemo が示唆するように)、クリーンアップ ハンドラから pthread_exit を呼び出したか (user315052 が示唆するように)、または他の何かが発生した可能性があります。ただし、バグのある実装や非準拠の実装を使用していない限り、「pthread_join() と pthread_exit() の間の競合状態」ではありません。

于 2012-07-11T22:54:11.877 に答える