web-dev-qa-db-ja.com

マルチスレッドコードを単体テストするにはどうすればよいですか?

マルチスレッドコードの競合状態とデッドロックを単体テストする方法はありますか?

彼らがあるべき姿を実行しているかどうかを確認するには...

34
Tamara Wijsman

[〜#〜] chess [〜#〜] 、Microsoft Researchのプロジェクト。彼らのサイトの引用:

CHESSは、並行プログラムでハイゼンバグを見つけて再現するためのツールです。 CHESSは、同時テストを繰り返し実行して、すべての実行で異なるインターリーブが実行されることを確認します。インターリーブの結果としてエラーが発生した場合、CHESSはインターリーブを再現してデバッグを改善できます。 CHESSは、マネージプログラムとネイティブプログラムの両方で使用できます。

Update(9/23/2015):C、C++、およびGoの場合、 ThreadSanitizer を使用できます。

19
Josh Kelley

Valgrind には Helgrind があり、本当に役立ちます。飢餓やデッドロックにつながる可能性のあるレースを指摘するのに役立つだけでなく、プログラムのプロファイルを作成することのわずかな速度低下により、他の方法では見られないレースが明らかになる場合があります。

だから、あなたが何らかのロックフリーの方法でコマンドーに行ったとしても、それはまだ役立ちます:)

ただし、POSIX中心です。 TAPのような単純な単体テストライブラリが実行されていることを簡単に認識できるヘッダーが同梱されており、これも非常に役立ちます。たとえば、飢餓をシミュレートするために、ロックを取得しようとしたときに通常はブロックされないスレッドを先に進めて(おそらくランダムに)ブロックすることができます。

10
Tim Post

詳細は正確には覚えていませんが、これは一般的な考え方です。そして、私はそれを1度だけ行いましたが、私がしたことは、タスククラスをモックできるようにインターフェイスを使用して、タスクを実行するコードからリエントラントコードを分離することでした。

次に、スレッドがクリティカルセクションにあることを確認できるようにモックアップを設計し、スレッドがクリティカルセクションにあることを確認してから、もう一度呼び出して待機していることを確認してから、最初のスレッドを解放し、正常に終了しました。

そんな感じ。

これがより複雑なシナリオで機能するかどうかはわかりませんが、リファクタリング中の動作を維持するのに役立ちます。

今年のJAOO/GOTOでこのプレゼンテーションを見ました。

http://gotocon.com/aarhus-2010/presentation/Testing%20Asynchronous%20Behaviour%20in%20an%20Instant%20Messaging%20Server

トリックは、呼び出し手順とアプリケーションの実際の操作の観点から、ヘアボールアプリケーションが実行することになっているものをモデル化することです。次に、John Hughesソフトウェアは、parallelで呼び出し手順の多くの順列を繰り返し試行し、その後、アプリケーションの状態がモデルの状態に対応していることを確認します。エラーが見つかった場合、ソフトウェアは、エラーを生成する最小限のケースにステップを減らす方法を知っています。

彼は15年間潜伏していて時々報告されているコアErlangライブラリのいくつかのバグをキャッチする方法をライブで示しましたが、それらがどこから来たのか、したがって修正方法を理解することはできませんでした。ソフトウェアによって報告された最小限のケースで、ライブラリーのメンテナーはday以内に各バグを修正することができました。

それはSO印象的でした。

John Hughesはこのソフトウェアを彼の会社を通じて販売しています。

2
user1249
  1. 再現性のない結果を伴うテストは役に立たない。それは完全にランダムなテストを除外しますが、疑似ランダムシーケンスから生成されたテストを残します。
  2. 並行環境のすべてのアクターには、従来の方法でテストできるアルゴリズムまたは非並行コンポーネントがあります。それらをテストすると、残りの障害は同時実行ロジックにあるはずです。
  3. 並行システムのイベントは、実際には常に線形のイベントシーケンスです。時間の測定に十分な精度が使用されている場合、「同時に」発生するイベントはありません。つまり、イベントを順次生成することで、並行システムのアクターをテストできます。並行システムの障害が発生した前後の一連のイベントをキャプチャすると、必要なテストケースが提供されます。
  4. アクターに活性(スレッド)を提供するコードは、オペレーティングシステムまたはシステムライブラリでは提供されないことがよくあります。上記のコードをテストする必要がないと想定しても安全です。通信と同期を担当するコードは、通常、アプリケーションプログラマによって記述されます。そのコードは、システムコードを呼び出さずに、つまりスレッドを起動せずにテストできます。
  5. アルゴリズムコード(キューが空)の境界条件は、多くの場合、同期コードでの処理を必要とします。これは、テストの適切なターゲットです。
  6. システムコード(t.wait())の周囲にプロキシを定義すると、テスト中に機能のスタブ/モックを使用できます。
2
Apalala

私の Relacy Race Detector を試してみてください。プロデューサー/コンシューマーキューや並行コンテナーなどの同期アルゴリズムを慎重かつ正確に検証するように設計されていますが、プログラム全体の検証にはあまり適していません。ただし、同期とミューテックスをプログラム全体に分散させることをお勧めしますが、代わりに(Relacyで検証できる)専用コンポーネントに同期を集中させることをお勧めします。

1
Dmitry Vyukov

簡単ではありませんが、基本的には、マルチスレッドコードを複数のスレッドから同時に呼び出すおよびタイミングと順序をランダムに変更するランダムThread.sleep()およびThread.yield()呼び出し(Javaを想定)。

上記のようなことを行うツール(TestNGなど)も用意されていますが、私が知る限り、まだ十分に成熟していません。

0
Joonas Pulakka

厳密な単体テストではありませんが、テストが断続的に失敗するテストに役立つランタイムチェックです。それは速くて汚いですが、うまくいきました。

Mutexが許可されると、どのスレッドがそれを持っているかを追跡します。すべてのmutexリクエストには30秒のタイムアウトがあり、その後、デッドロックを叫びます。

次に、許可されたミューテックスのリストを使用して、ブロッキングミューテックスを保持しているスレッド、およびその理由を確認できます。これまでの私のケースでは、それは何か他のものに行き詰まっているためです。それで、その状況を修正することができます。

ミューテックスにはクロスプラットフォームのラッパークラスがあり、レコードの保持とタイムアウトを簡単に挿入できるため、これは私にとってはうまくいきました。また、ミューテックスで30秒間ブロックされてはならないことを知るのに十分なアプリケーションについても知っていました。

これは完全に汎用的な目的ではないかもしれませんが、約2時間のプログラミング作業で多くのデバッグを節約できます。オーバーヘッドはごくわずかで、デバッグビルドのみが可能です。

ネストされたミューテックス要求シーケンスを記録するためにそれを拡張することを見て、実際にデッドロックを引き起こすだけでなく、デッドロックを引き起こす可能性があるものがあるかどうかを確認します(たとえば、1つのスレッドがA、Bをロックし、別のスレッドがB、Aをロックします)。ささいな努力のために多くの利益をもたらしました。

0
Andy Krouwel