20

ちょうど5分前にインタビューをしましたが、3つの質問には答えませんでした。誰かが私を助けてくれませんか。

質問:

マルチスレッドアプリケーション関数でデッドロックシナリオを探し、それを防ぐ方法は?

私が与えた答え:

デッドロックとロック、ミューテックス、モニター、セマフォの定義を示しました。彼は私に、これらはツールであると言いましたが、これらのツールを盲目的に使用すると、彼が言ったパフォーマンスが犠牲になるため、デッドロックシナリオを探す方法:(

これを理解するのを手伝ってください。

4

4 に答える 4

12

デッドロックがどのように発生し、どのように防止できるかを説明するのに問題があったようです。

デッドロックは、各スレッド(2つ以上)が別のスレッドによってすでにロックされているリソースのロックを取得しようとしたときに発生します。リソース1でロックされたスレッド1は、リソース2でロックを取得しようとします。同時に、スレッド2はリソース2でロックを取得し、リソース1でロックを取得しようとします。2つのスレッドがロックを放棄することはないため、デッドロックが発生します。発生します。

デッドロックを回避する最も簡単な方法は、タイムアウト値を使用することです。Monitorクラス(system.Threading.Monitor)は、ロックの取得中にタイムアウトを設定できます。

try{
    if(Monitor.TryEnter(this, 500))
    {
        // critical section
    }
}
catch (Exception ex)
{

}
finally
{
    Monitor.Exit();
}

続きを読む

于 2013-03-12T13:14:32.117 に答える
5

パフォーマンス分析ツールは、特にデッドロックの特定にも役立ちます。この質問は、このトピックに関する洞察を提供します:競合状態/デッドロックを見つけるための C#/.NET 分析ツール

コードを視覚的に分析し、ロックを適切に使用することも役立ちます (検査中にコードの潜在的な問題を検出できるはずです) が、複雑なアプリケーションでは非常に困難な場合があります。デッドロックは、単にコードを検査するだけではなく、コードを実行したときにのみ表示される場合があります。

私はあなたのインタビュアーのことをあまり知りません。ロック標準/ガイドラインについてどれだけ知っているかを確認したい人もいれば、ツールの使用方法を知っているかどうかを確認したい人もいれば、両方が必要な人もいます。たとえば、私が働いている会社では、ツール (特に、既に所有して使用しているツール) の使用が高く評価されています。しかし、だからと言って、コーディングのデッドロックを最初から防ぐスキルを身につけるべきではないという意味ではありません。

ロックのためだけに何かをロックすると、スレッドが互いに待機するため、パフォーマンスに影響します。ワークフローを分析して、本当にロックする必要があるものを、いつ、どのタイプのロック (シンプルlockまたはReaderWriterLockSlim. デッドロックを防ぐための一般的な方法は多数あります。

たとえばReaderWriterLockSlim、タイムアウトを使用してデッドロックを防ぐことができます (待機しすぎると、ロックの取得を中止します)。

if (cacheLock.TryEnterWriteLock(timeout))
{
...
}

そして、そのようなタイムアウトを提案できるはずです。

そのような質問では、ネストされたロックの不適切な使用など、デッドロックの古典的なケースについて少なくとも言及することを期待します(それらを回避できるか、なぜそれらが悪いのかなどを知ることができるはずです)。

この主題は非常に大きく、これについてはいくらでも話せます。しかし、定義なし。ロックとは何かを知ることと、大規模なマルチスレッド アプリケーションでロック/セマフォ/ミューテックスを使用することを知ることは、2 つの異なることです。

于 2013-03-12T13:12:41.213 に答える
4

面接はあなたにひっかけ質問をしていると思います。静的解析を使用してデッドロックを防ぐことができれば...誰もデッドロックを起こすことはありません!

個人的には、デッドロックを探すときは、クリティカル セクションが関数呼び出しを超えている関数を見つけることから始めます。例えば

void func(){
    lock(_lock){
        func2();
     }
}

何をしているのかははっきりしていませんfunc2。同じスレッドでイベントをディスパッチする可能性があります。これは、イベントがまだクリティカル セクションの一部であることを意味します。多分それはのロックをロックします。たぶん、それはスレッドプールにディスパッチされ、別のスレッドにあるため、再入可能ではなくなりました! これらの種類の場所で、デッドロック シナリオが発生し始める可能性があります。複数の再入不可のロック場所がある場合です。

また、デッドロック シナリオをトレースするときに、後戻りして、すべてのスレッドが作成された場所を見つけようとすることもあります。各機能と、実際に実行できる場所を考えます。よくわからない場合は、関数呼び出しの発信元をログに記録するログを追加することも役立ちます。

ロックフリーのデータ構造を使用することで、デッドロックを回避することもできます (ただし、それらを使用するには同じくらい多くのことが必要です)。アクセスするたびに変更される可能性があるため、ロックフリー構造へのアクセスを最小限に抑えたいと考えています。

別の回答で述べたように、タイムアウト付きのミューテックスを使用できますが、常に機能するとは限りません (コードがタイムアウトよりも長く機能する必要がある場合はどうなりますか?)。別のコメントで、これはインタビュアーが求めていたものかもしれないと言及されていました. 本番環境では、これはあまり良い考えではありません。タイムアウトは常に変化します。何かが実行されてタイムアウトになるまでに予想以上に時間がかかった可能性があります。デッドロックさせてプロセスダンプを取得し、ロックを保持していたものを正確に見つけて問題を修正する方がよいと思います。もちろん、ビジネス要件でそれが許可されていない場合は、これを防御コーディング戦略の一部として使用し、スマート ロックの配置を選択することもできます。

ロックが常に大きなパフォーマンスの問題を引き起こすというあなたのインタビューには同意しません。競合しないロック/ミューテックス/etc は、OS に渡す前にスピンロックとして最初にテストされ、スピンロックは安価です。

一般に、デッドロックを回避する最善の方法は、プログラム フローを理解することです。新しいロック オブジェクトを導入するたびに、それがどこで使用され、チェーンの下流で何が使用されるかを考えてください。

于 2013-03-12T13:09:47.683 に答える
1

この問題の最も簡単な解決策は、常に十分なタイムアウトでスリープ/待機することです。そのタイムアウトが発生した場合、何かが必要以上に長くかかっていることがわかり、デッドロックや別のバグが発生する可能性が高くなります。

Mutex m; // similar overloads exist for all locking primitives
if (!m.WaitOne(TimeSpan.FromSeconds(30)))
    throw new Exception("Potential deadlock detected.");

WaitOne戻ったときfalse、それは 30 秒間待機し、ロックはまだ解除されていません。ロックされたすべての操作がミリ秒以内に完了する必要があることがわかっている場合 (そうでない場合は、タイムアウトを増やしてください)、これは何かがうまくいかなかったという非常に良い兆候です。

于 2013-03-12T13:03:31.190 に答える