12

クライアントが抱えている問題を解決するのを支援します。私はシステム管理者/DBAの人なので、彼らを助けるのに苦労しています。彼らはそれがカーネル/環境のバグだと言っています、私はそれが彼らのコードにあると主張するか、OSのベンダーサポートを求める前にそれを証明または反証しようとしています。

RedHatおよびOracleEnterpriseLinux 5.7(および5.8)で発生し、アプリケーションはC++で記述されています

彼らが経験している問題は、メインスレッドが別のスレッドを開始して、実行時間が長くなる可能性のあるTCP connect()[サーバーに接続しているクライアント]を実行することです。「長時間実行」アスペクトに時間がかかりすぎる場合、スレッドをキャンセルして別のスレッドを開始します。

これは、サーバープログラムの状態がわからないために行われます。

  • サーバープログラムが起動して実行中->接続がすぐに受け入れられました
  • サーバープログラムが実行されていない、マシンとネットワークがOK->接続がすぐに失敗し、エラー「接続が拒否されました」
  • マシンまたはネットワークがクラ​​ッシュまたはダウンしました->接続が失敗するのに長い時間がかかりますエラー「ホストへのルートがありません」

問題は、ミューテックスがロックされているスレッドをキャンセルすると(ミューテックスのロックを解除するようにクリーンアップハンドラーが設定されている場合)、ミューテックスのロックが解除されない場合があることです。

そのため、ミューテックスをロックしようとするとメインスレッドがハングしたままになります。

詳細な環境情報:

  • glibc-2.5-65
  • glibc-2.5-65
  • libcap-1.10-26
  • kernel-debug-2.6.18-274.el5
  • glibc-ヘッダー-2.5-65
  • glibc-common-2.5-65
  • libcap-1.10-26
  • kernel-doc-2.6.18-274.el5
  • カーネル-2.6.18-274.el5
  • kernel-headers-2.6.18-274.el5
  • glibc-devel-2.5-65

コードは次のコマンドで作成されました:c ++ -g3 tst2.C -lpthread -o tst2

アドバイスやガイダンスは大歓迎です

4

2 に答える 2

18

キャンセルされたスレッドが保持しているミューテックスのロックを解除しないのは正しいことです。手動で実行するように調整する必要があります。これは、可能なすべてのキャンセルポイントで適切なクリーンアップハンドラーを使用するように非常に注意する必要があるため、注意が必要です。pthread_cancelスレッドをキャンセルするために使用し、ミューテックスのロックを解除するためにクリーンアップハンドラーを設定していると仮定するとpthread_cleanup_push、正しく実行するのが簡単で信頼性が高い可能性のあるいくつかの選択肢があります。

RAIIを使用してミューテックスのロックを解除する、信頼性が高まります。GNU / Linuxではpthread_cancel、タイプの特別な例外を使用して実装されている__cxxabi::__forced_unwindため、スレッドがキャンセルされると、例外がスローされ、スタックがアンワインドされます。ミューテックスがRAIIタイプによってロックされている場合、スタックが例外によって巻き戻された場合、そのデストラクタは実行されることが保証され__forced_unwindます。 Boost ThreadPthreadをラップし、はるかに使いやすいポータブルC++ライブラリを提供します。RAIIタイプboost::mutexおよびその他の有用な抽象化を提供します。Boost Threadは、Pthreadのキャンセルに似ているが同じではない独自の「スレッド中断」メカニズム、およびPthreadのキャンセルポイント(connect)はブーストスレッドの中断ポイントではありません。これは、一部のアプリケーションに役立つ場合があります。ただし、クライアントの場合、キャンセルのポイントはconnect呼び出しを中断することであるため、クライアントはおそらくPthreadのキャンセルに固執したいと考えています。GNU / Linuxが例外としてキャンセルを実装する(移植性のない)方法は、それがでうまく機能することを意味しboost::mutexます。

C ++で記述しているときに、ミューテックスを明示的にロックおよびロック解除する言い訳はありません。IMHOのC ++の最も重要で最も便利な機能は、ミューテックスロックなどのリソースを自動的に解放するのに理想的なデストラクタです。

pthread_mutexattr_setrobustもう1つのオプションは、ミューテックスを初期化するpthread_mutexattr_t前にを呼び出すことによって作成される堅牢なミューテックスを使用することです。堅牢なミューテックスを保持しているときにスレッドが停止すると、カーネルはそのスレッドを記録して、ミューテックスをロックしようとする次のスレッドが特別なエラーコードを取得するようにしますEOWNERDEAD。可能であれば、新しいスレッドは、スレッドによって保護されたデータを再び一貫性のあるものにし、ミューテックスの所有権を取得することができます。これは、単にRAIIタイプを使用してミューテックスをロックおよびロック解除するよりも、正しく使用するのがはるかに困難です。

まったく異なるアプローチは、を呼び出すときに本当にミューテックスロックを保持する必要があるかどうかを判断することですconnect。低速操作中にミューテックスを保持することはお勧めできません。connect正常にミューテックスをロックし、ミューテックスによって保護されている共有データを更新した場合、電話をかけることはできませんか?

私の好みは、Boost Threadを使用することと、ミューテックスを長期間保持しないことの両方です。

于 2013-01-10T22:45:32.107 に答える
4

彼らが経験している問題は、メインスレッドが別のスレッドを開始して、実行時間が長くなる可能性のあるTCP connect()[サーバーに接続しているクライアント]を実行することです。「長時間実行」アスペクトに時間がかかりすぎる場合、スレッドをキャンセルして別のスレッドを開始します。

簡単な修正-スレッドをキャンセルしないでください。害はありますか?connect必要に応じて、接続がまだ必要かどうかをスレッドでチェックし(finallyが完了したとき)、必要でない場合は、接続を閉じ、ミューテックスを解放して終了します。これは、ミューテックスで保護されたブール変数を使用して行うことができます。

また、ネットワークI / Oを待機している間、スレッドはミューテックスを保持してはなりません。ミューテックスは、高速で、主にCPUが制限されているか、ローカルディスクによって制限されているものにのみ使用する必要があります。

最後に、外側から手を伸ばしてスレッドに何かを強制する必要があると感じた場合は、一歩下がってください。そのスレッドのコードを作成しましたその必要性を感じた場合、それはあなたが本当にやりたいことをするためにそのスレッドをコーディングしなかったことを意味します。修正は、スレッドを変更して、実際に必要なことだけを実行することです。そうすれば、外部から「押し回す」必要がなくなります。

于 2013-01-11T01:24:54.207 に答える