web-dev-qa-db-ja.com

マルチスレッドの競合状態のテスト

これへのコメントを読む answer 、特に:

テストを記述できないからといって、テストが壊れていないわけではありません。予期しない動作が通常発生する未定義の動作(CおよびC++はそれでいっぱいです)、競合状態、メモリモデルが弱いために順序が変更される可能性があります... – CodesInChaos7時間前

@CodesInChaos再現できない場合、「修正」するために書かれたコードもテストできません。そして、テストされていないコードをライブに置くことは、私の考えではより悪い犯罪です-RhysW5時間前

...テストケースの競合状態が原因で、非常にまれにしか発生しない本番環境の問題を一貫してトリガーする一般的な方法があるかどうか疑問に思っています。

1978年頃からこのクレイジービジネスに携わってきた後、ほぼすべての時間を組み込みリアルタイムコンピューティング、マルチタスク、マルチスレッド、マルチシステム、場合によっては複数の物理プロセッサでの作業に費やして、私の公平な競争よりも多くを追い求めてきました。条件、私の考えられた意見はあなたの質問への答えは非常に簡単であるということです。

番号。

テストで競合状態を引き起こす一般的な方法はありません。

あなたの唯一の希望はあなたのシステムから完全にそれらを設計することです。

誰かが誰かを詰め込んでいるのを見つけたら、あなたは彼を蟻塚から取り除き、それからそれを排除するために再設計するべきです。あなたのシステムから彼ののどのパス(f *** upと発音します)を設計したら、アリから彼を解放することができます。 (蟻がすでに彼を食べ尽くして骨だけを残している場合は、「これはXYZプロジェクトにレース条件を入れた人々に何が起こるかです!」

89
John R. Strohm

Msツールチェーンにいる場合。 Ms Researchは、実行ごとに新しい関連付けを強制し、失敗した実行をその呼び出された chess を再作成できるツールを作成しました。

こちらが video 使用中の様子です。

16
rerun

これらの種類の問題について私が知っている最良のツールは、 Helgrind と呼ばれるValgrindの拡張です。

基本的にValgrindは仮想プロセッサをシミュレートし、その上でバイナリ(変更なし)を実行するため、メモリへのすべてのアクセスをチェックできます。そのフレームワークを使用して、Helgrind監視システムは、共有変数へのアクセスが相互排除メカニズムによって適切に保護されていない場合を推測するように呼び出します。これにより、実際には発生していなくても、理論上の競合状態を検出できます。

Intelは Intel Inspector と呼ばれる非常に類似したツールを販売しています。

これらのツールは素晴らしい結果をもたらしますが、プログラムは分析中にかなり遅くなります。

16
Julien

マルチスレッドのバグを公開するには、異なる実行スレッドに特定のインターリーブされた順序でステップを実行させる必要があります。通常、これは、手動でデバッグしたり、このインターリーブを制御するための何らかの「ハンドル」を取得するためにコードを操作したりすることなく行うのは困難です。しかし、予測できない動作をするコードを変更すると、その予測不能性に影響を与えることが多いため、これを自動化するのは困難です。

ナイストリックはJaroslav Tulachによって Practical API Design で説明されています。問題のコードにロギングステートメントがある場合は、consumerそれらのロギングステートメント(たとえば、挿入された疑似ターミナル)の内容に基づいて特定の順序で個々のログメッセージを受け入れるようにします。これにより、まだ存在しない実稼働コードに何も追加する必要なく、さまざまなスレッドでのステップのインターリーブを制御できます。

8
Kilian Foth

さまざまな種類の未定義の動作(特に競合状態)が存在しないことを確実に確認する方法はありません。

ただし、このような状況を多数示すツールは多数あります。修正が有効であることを証明できない場合でも、そのようなツールで問題が存在することを証明できる場合があります。

この目的のためのいくつかの興味深いツール:

Valgrindはメモリチェッカーです。メモリリーク、初期化されていないメモリの読み取り、ダングリングポインターの使用、境界外のアクセスを検出します。

Helgrindはスレッドセーフティチェッカーです。競合状態を検出します。

どちらも動的なインストルメンテーションによって機能します。つまり、プログラムを現状のままにして、仮想化された環境で実行します。これはそれらを邪魔にならないが遅くします。

UBSanは未定義の動作チェッカーです。整数オーバーフロー、範囲外のシフトなど、CおよびC++の未定義の動作のさまざまなケースを検出します。

MSanはメモリチェッカーです。 Valgrindと同様の目標があります。

TSanはスレッドセーフティチェッカーです。 Helgrindと同様の目標があります。

これら3つはClangコンパイラに組み込まれており、コンパイル時にコードを生成します。これは、それらをビルドプロセスに統合する必要があることを意味します(特に、Clangでコンパイルする必要があります)。これにより、* Grindよりも初期設定がはるかに難しくなりますが、一方で、実行時のオーバーヘッドははるかに低くなります。

リストしたすべてのツールはLinuxで動作し、一部はMacOSで動作します。 Windowsでの動作はまだ信頼できるとは思いません。

6
Sebastian Redl

ここでの答えのほとんどは、この質問を「どのようにして自動的に競合状態を検出するのですか?」と誤解しているようです。質問が本当に「テストで競合状態を見つけたら、どうやって再現するか」です。

それを行う方法は、テストのみに使用される同期をコードに導入することです。たとえば、イベントAとイベントBの間にイベントXが発生したときに競合状態が発生した場合、アプリケーションをテストするために、イベントAの発生後にイベントXが発生するのを待つコードを記述します。テストがアプリケーションと通信してそれを伝えるための何らかの方法が必要になる可能性があります(「私はこれをテストしているので、この場所でこのイベントを待つ」)。

私はnode.jsとmongoを使用しています。いくつかのアクションでは、複数のコレクションで一貫したデータを作成する必要があります。これらの場合、ユニットテストはアプリケーションに呼び出しを行い、「イベントXの待機を設定する」と伝えます。アプリケーションが設定すると、イベントXのテストが実行され、その後、テストはアプリケーション(「イベントXの待機が完了した」)なので、残りのテストは正常に実行されます。

ここでの答えは、Pythonのコンテキストでこのタイプのことを詳細に説明しています: https://stackoverflow.com/questions/19602535/how-can-i-reproduce-the-race-conditions-in-this- python-code-reliably

2
B T