31

私が最初に順応するのが最も難しかったことの 1 つは、C で pthreads を使ったプログラミングを初めて経験したときでした。私は、実行されるコードの次の行が何であるかを正確に知ることに慣れており、私のデバッグ手法のほとんどは、その期待に基づいていました。

C で pthreads を使用してデバッグするための優れた手法は何ですか? 追加のツール、使用するツール、またはデバッグに役立つその他のものを使用せずに、個人的な方法論を提案できます。

PS Linuxでgccを使用してCプログラミングを行っていますが、必ずしも答えを制限しないでください

4

8 に答える 8

32

Valgrindは、競合状態と pthreads API の誤用を見つけるための優れたツールです。プログラム メモリ (およびおそらく共有リソース) アクセスのモデルを保持し、バグが無害であってもロックの欠落を検出します (もちろん、後で完全に予想外に無害になることを意味します)。

valgrind --tool=helgrindそれを使用するには、を呼び出します。ここにそのマニュアルがありますvalgrind --tool=drd説明書)もあります。Helgrind と DRD は異なるモデルを使用しているため、重複しているがおそらく異なる一連のバグを検出します。偽陽性も発生する可能性があります。

とにかく、valgrind のおかげで数え切れないほどのデバッグ時間を節約できました (すべてではありませんが :)。

于 2009-06-11T16:05:54.510 に答える
7

スレッド化されたプログラムのデバッグで驚かされることの 1 つは、しばしばバグの変更を見つけたり、printf を追加したり、デバッガーでプログラムを実行したりすると消えてしまうことです (通称Heisenbugとして知られています)。

スレッド化されたプログラムでは、ハイゼンバグは通常、競合状態があることを意味します。優れたプログラマーは、順序に依存する共有変数またはリソースを探します。くだらないプログラマーは、sleep() ステートメントでやみくもに修正しようとします。

于 2009-06-11T13:44:12.570 に答える
2

「考える」フェーズでは、コーディングを開始する前に、ステート マシンの概念を使用します。デザインをより明確にすることができます。

printf は、プログラムのダイナミクスを理解するのに役立ちます。しかし、それらはソース コードを乱雑にするため、マクロ DEBUG_OUT() を使用し、その定義でブール フラグを使用して有効にします。さらに良いことに、「kill -USR1」を介して送信するシグナルでこのフラグを設定/クリアします。出力をタイムスタンプ付きのログ ファイルに送信します。

また、assert() の使用を検討してから、gdb と ddd を使用してコア ダンプを分析してください。

于 2010-02-13T15:17:25.997 に答える
2

マルチスレッド アプリケーションのデバッグは困難です。*nix 環境用のGDB (オプションのDDDフロント エンド付き)などの優れたデバッガーや、Windows の Visual Studio に付属するデバッガーは非常に役立ちます。

于 2009-06-11T13:28:12.720 に答える
1

私はほとんどの場合、もっぱらマルチスレッドの高性能な世界で開発を行っているので、私が使用する一般的な方法を次に示します。

設計 - 最良の最適化はより優れたアルゴリズムです:

1)機能を論理的に分離可能な部分に分割します。
これは、呼び出しが「A」と「A」のみを実行することを意味します-A、B、C ではなく... 副作用を完全になくすことができない場合は、副作用をいくつかの場所に分離します (コードに集中させます)。
3) できるだけ多くの分離されたコンポーネントを RE-ENTRANT にします。これは、ステートレスであることを意味します。すべての入力を定数として受け取り、宣言された論理定数パラメーターのみを操作して出力を生成します。可能な限り、参照ではなく値渡し。
4) ステートがある場合は、ステートレス サブアセンブリと実際のステート マシンを明確に分離します。ステート マシンは、ステートレス コンポーネントを操作する単一の関数またはクラスであることが理想的です。

デバッグ:

スレッディングのバグは、競合とデッドロックという 2 つの広範なフレーバーで発生する傾向があります。原則として、デッドロックははるかに決定論的です。

1) データの破損が見られますか?: はい => おそらく競合です。
2) バグはすべての実行で発生しますか、それとも一部の実行で発生しますか?: はい => デッドロックの可能性があります (レースは一般的に非決定論的です)。
3) プロセスがハングすることはありますか?: はい => どこかでデッドロックが発生しています。たまにしかハングしない場合は、競合も発生している可能性があります。

ブレークポイントは、コード内の同期プリミティブ THEMSELVES のように動作することがよくあります。これは、論理的に類似しているためです。他のコンテキスト (ユーザー) が再開する信号を送信するまで、現在のコンテキストで強制的に実行を停止させます。これは、マルチスレッドの動作を変更するものとしてコード内にあるブレークポイントを表示する必要があることを意味します。ブレークポイントは競合状態に影響しますが、(一般に) デッドロックには影響しません。

原則として、これは、すべてのブレークポイントを削除し、バグの種類を特定してから、それらを再導入して修正する必要があることを意味します。そうでなければ、物事をさらに歪めるだけです。

于 2014-07-17T17:15:20.347 に答える
1

マルチスレッド デバッグへの私のアプローチはシングル スレッドと似ていますが、通常は考える段階により多くの時間が費やされます。

  1. 何が問題を引き起こしているのかについての理論を展開します。

  2. 理論が正しい場合にどのような結果が期待できるかを判断します。

  3. 必要に応じて、結果と理論を反証または検証できるコードを追加します。

  4. あなたの理論が正しいなら、問題を解決してください。

多くの場合、理論を証明する「実験」は、疑わしいコードの周りにクリティカル セクションまたはミューテックスを追加することです。次に、クリティカル セクションを体系的に縮小して、問題を絞り込みます。クリティカル セクションは、常に最適な修正とは限りません (ただし、多くの場合、迅速な修正になる可能性があります)。ただし、「喫煙銃」を特定するのに役立ちます。

前述したように、同じ手順がシングル スレッド デバッグにも適用されますが、デバッガーにジャンプして実行するのは非常に簡単です。マルチスレッド デバッグでは、コードをより深く理解する必要があります。デバッガーを使用してマルチスレッド コードを実行しても、何の役にも立たないことがよくあるからです。

また、ヘルグラインドは優れたツールです。Intel のスレッド チェッカーは、Windows で同様の機能を実行しますが、コストはヘルグラインドよりもはるかに高くなります。

于 2009-06-12T01:22:23.063 に答える
0

私は多くのブレークポイントを使用する傾向があります。スレッド関数を実際には気にしないが、その副作用を気にする場合は、スレッド関数が終了するか、待機状態にループバックするか、またはその他の処理を行う直前にチェックするのが良い時期です。

于 2009-06-11T13:34:34.623 に答える
0

マルチスレッド プログラミングを始めたとき、デバッガーの使用をやめました。私にとって重要なポイントは、優れたプログラムの分解とカプセル化です。

モニターは、エラーのないマルチスレッド プログラミングの最も簡単な方法です。複雑なロックの依存関係を回避できない場合は、それらが循環的であるかどうかを簡単に確認できます。プログラムがハングするまで待ってから、「pstack」を使用してスタックトレースを確認してください。いくつかの新しいスレッドと非同期通信バッファーを導入することで、循環ロックを解除できます。

アサーションを使用し、ソフトウェアの特定のコンポーネントに対してシングルスレッドの単体テストを作成してください。必要に応じて、デバッガーでそれらを実行できます。

于 2012-09-19T20:28:08.957 に答える