web-dev-qa-db-ja.com

マルチスレッドの問題を検出してデバッグする方法は?

これは this question へのフォローアップであり、この点については何も入力しませんでした。ここに簡単な質問があります:

マルチスレッドコードに起因する問題を検出してデバッグすることは可能ですか?

「ここでは問題を再現できないため、修正できません。問題を再現する手順を教えてください。それから修正します。」それがマルチスレッドの問題であることを知っている場合、それは何らかの形で厄介な答えですが、ほとんど私はそうではありません。問題がマルチスレッドの問題であることを知り、デバッグする方法を知るにはどうすればよいですか?

特別なロギングフレームワーク、デバッグテクニック、コードインスペクターなど、このような問題の解決に役立つものがあるかどうかを知りたいです。一般的なアプローチを歓迎します。回答が言語に関連する必要がある場合は、.NETおよびJavaに保管してください。

62
MicSim

スレッド化/同時実行性の問題複製が難しいことで有名です-これは、確率を回避するか、少なくとも最小化するように設計する必要がある理由の1つです。これが、不変オブジェクトが非常に貴重な理由です。可変オブジェクトを単一のスレッドに分離してから、スレッド間の可変オブジェクトの交換を慎重に制御してください。 「共有」オブジェクトではなく、オブジェクトの引き渡しの設計でプログラミングを試みます。後者の場合、完全に同期化された制御オブジェクト(推論する方が簡単です)を使用し、同期化オブジェクトに、同期化する必要がある他のオブジェクトを利用させないようにします。あなたの最高の防御は良いデザインです。

Deadlocksは、デッドロック時にスタックトレースを取得できる場合、デバッグが最も簡単です。ほとんどがデッドロック検出を行うトレースを考えると、理由を正確に特定し、コードを修正する理由と方法を簡単に特定できます。デッドロックの場合、同じロックを異なる順序で取得することは常に問題になります。

ライブロックはより困難です-エラー状態にある間にシステムを監視できることが最善の策です。

レース条件は複製するのが非常に難しい傾向があり、手動のコードレビューから特定するのはさらに困難です。これらを使用して、私は通常、再現する広範なテストに加えて、可能性について推論し、理論を証明または反証するために情報を記録しようとします。状態の破損の直接的な証拠がある場合は、破損に基づいて考えられる原因について推論することができます。

システムが複雑になればなるほど、同時実行エラーを発見し、その動作について推論することが難しくなります。 JVisualVMやリモート接続プロファイラーなどのツールを使用します。エラー状態のシステムに接続してスレッドとオブジェクトを検査できる場合、これらは命の恩人になります。

また、CPUコアの数、パイプライン、バス帯域幅などに依存する可能性のある動作の違いに注意してください。ハードウェアの変更は、問題を再現する能力に影響を与える可能性があります。一部の問題はシングルコアCPUでのみ表示され、その他の問題はマルチコアでのみ表示されます。

最後に、システムライブラリで配布されている同時実行オブジェクトを使用してみます-例:Java Java.util.concurrent あなたの友だちです。 独自の同時実行制御オブジェクトの作成は難しく、危険に満ちています。選択があれば、専門家に任せてください。

78
Lawrence Dol

answer あなたが 他の質問 に到達したのはかなり良かったと思いました。しかし、これらの点を強調します。

クリティカルセクションの共有状態のみを変更する(相互排除)

設定された順序でロックを取得し、反対の順序でロックを解放します。

可能な限り事前に構築された抽象化を使用する(Java.util.concurrentのようなもの)

また、一部の分析ツールは潜在的な問題を検出できます。たとえば、 FindBugs は、Javaプログラムでスレッドの問題を見つけることができます。そのようなツールはすべての問題を見つけることはできません(それらは特効薬ではありません).

vanslly がこの回答へのコメントで指摘しているように、適切に配置されたロギング出力を調べることも非常に役立ちますが、 Heisenbugs に注意してください。

7
Greg Mattes

Javaと呼ばれる検証ツールがあります javapathfinder これは、コードからの潜在的な競合状態とデスロックバグに対してマルチスレッドアプリケーションをデバッグおよび検証するのに役立ちます。 。
EclipseとNetbean IDEの両方でうまく動作します。

5
bLaXjack

再現するのが難しいトラブルの報告があると仮定すると、コードを読むことで、できればペアコードを読むことで常に見つけるので、スレッドのセマンティクス/ロックの必要性について議論できます。 報告された問題に基づいてこれを行うと、常に1つ以上の問題をかなり迅速に発見できます。また、難しい問題を解決するためのかなり安価な手法だと思います。

Ctrl + shift + f13を押すように指示できないことを申し訳ありませんが、そのようなものが利用できるとは思いません。しかし、what報告された問題を実際に考えてみてくださいisは、通常、コードにかなり強い方向感覚を与えます。そのため、main()から始める必要はありません。

5
krosenvold

すでに得られている他の良い答えに加えて、少なくとも、顧客が使用している数以上のプロセッサ/プロセッサコア、またはプログラムにアクティブなスレッドがあるマシンでテストしてください。そうしないと、マルチスレッドのバグの一部を再現するのが難しくなる可能性があります。

5
mghie

クラッシュダンプとは別に、手法は大規模なランタイムロギングです。各スレッドは、実行中のログを記録します。

エラーが報告されたときの最初の質問は、「ログファイルはどこですか?」

ログファイルで問題を確認できる場合があります。「このスレッドは、ここで違法/予期しない状態を検出しています...そして、この他のスレッドがこれを行っていた、直前および直後、またはそのいずれかです」

ログファイルに何が起こっているのかがわからない場合は、顧客に謝罪し、十分に多くの追加のログステートメントをコードに追加し、新しいコードを顧客に提供し、もう一度発生した後に修正することを伝えます。

5
ChrisW

マルチスレッドソリューションを回避できない場合があります。バグがある場合、リアルタイムで調査する必要がありますが、これはVisual Studioなどのほとんどのツールではほとんど不可能です。唯一の実用的な解決策は、トレースを記述することですが、トレース自体は次のことを行う必要があります。

  1. 遅延を追加しない
  2. ロックを使用しない
  3. マルチスレッドを安全にする
  4. 正しい順序で何が起こったかを追跡します。

これは不可能な作業のように聞こえますが、トレースをメモリに書き込むことで簡単に達成できます。 C#では、次のようになります。

public const int MaxMessages = 0x100;
string[] messages = new string[MaxMessages];
int messagesIndex = -1;

public void Trace(string message) {
  int thisIndex = Interlocked.Increment(ref messagesIndex);
  messages[thisIndex] = message;
}

メソッドTrace()は、マルチスレッドに対して安全で、非ブロッキングであり、任意のスレッドから呼び出すことができます。私のPCでは、実行に約2マイクロ秒かかりますが、これは十分に速いはずです。

何か問題があると思われる場所にTrace()命令を追加し、プログラムを実行し、エラーが発生するまで待機し、トレースを停止してから、トレースのエラーを調査します。

スレッドとタイミング情報も収集し、バッファーをリサイクルし、トレースを適切に出力するこのアプローチの詳細な説明:CodeProject:リアルタイムでのマルチスレッドコードのデバッグ 1

3
Peter Huber

マルチスレッドコードのデバッグに留意するための、いくつかのデバッグ手法を含む小さなグラフ。チャートは成長しています。コメントやヒントを追加してください。 ( このリンク のファイルを更新します)

Multithreaded debugging chart

2
Mouze

ツールを実装しました vmlens Java実行時にプログラムで競合状態を検出します。 eraser と呼ばれるアルゴリズムを実装します。

1
Thomas Krieger

Visual Studioでは、各スレッドの呼び出しスタックを検査し、それらを切り替えることができます。あらゆる種類のスレッドの問題を追跡するのに十分ではありませんが、それは始まりです。今後のVS2010では、マルチスレッドデバッグの多くの改善が計画されています。

.NETコードのスレッド化の問題には、WinDbg + SoSを使用しました。ロック(同期ブロック)、スレッド呼び出しスタックなどを検査できます。

1
Brian Rasmussen

Tess Ferrandezのブログ には、WinDbgを使用して.NETのデッドロックをデバッグする良い例があります。

1
Sean

assert()は、競合状態を検出するための友達です。クリティカルセクションに入るたびに、それに関連付けられた不変式が真であると断言してください(CSの目的です)。ただし、残念ながら、このチェックは高価であるため、実稼働環境での使用には適さない場合があります。

1
zvrba

他の条件(メモリ、スケジューラ、処理負荷)がほぼ同じであるため、同じ間違った結果を与え、予測できない動作をしないスレッドの問題に直面しました。

私の経験から言えば、最も難しい部分はスレッドの問題であることを認識することであり、最良の解決策はマルチスレッドコードを注意深く確認することです。スレッドコードを注意深く見るだけで、何が間違っているのかを理解する必要があります。他の方法(スレッドダンプ、プロファイラなど)がそれに続きます。

0
Kuldeep Tiwari

コードの開発 プリンセスが他の質問に推奨した方法 (不変オブジェクト、およびアーランスタイルのメッセージパッシング)。スレッド間の相互作用が明確に定義されるため、マルチスレッドの問題を検出するのが簡単になります。

0
Sean