この質問についてどのくらい知っていますか?インタビューの質問:楽観的ロック、悲観的ロック、相互排除ロック、スピンロック、読み取り/書き込みロックアプリケーションシナリオ

いいねしてフォローすれば、迷子になることはありません!   

序文

インタビューに関して言えば、私たちは実際に多くの知識を簡単に習得することができますが、学習するために、謎を発見するためにコンピューターに深く入り込まなければならない多くのことがわかります。

多くの人が私にたくさんのことを覚える方法を尋ねます。実際、学ぶことは非常に無力なことです。私たちは学ばなければならないので、なぜ学ぶのは簡単ではないのですか?それを楽しむことを学ぶために?最近は基礎も作っていますが、後でコンピューターの基礎やネットワーク関連の知識を更新していきます。

日常生活で使われている錠前は比較的シンプルで失礼ですが、基本的には部外者の侵入や電気自動車の盗難などを防ぐことを目的としています。

しかし、人生にはバグがないわけではありません。たとえば、ロックされた電気自動車が「Guangxi-Stealing Guevara」の前にあり、ロックは役に立たないです。彼が望む限り、彼はあなたの電気自動車を「ShunGo」に簡単に渡すことができます。 「さもなければ、パートタイムの仕事はどうして彼の人生で不可能なことになるのだろうか?素晴らしい人々は素晴らしい場所を持っている必要があります。

プログラミングの世界では、「ロック」はさらに多様で多様であり、各タイプのロックのロックコストとアプリケーションシナリオも異なる場合があります。

ロックをうまく利用する方法も、プログラマーの基本的な資質の1つです。

同時実行性の高いシナリオでは、適切なロックを選択すると、システムのパフォーマンスが大幅に向上します。そうしないと、パフォーマンスが低下します。

したがって、さまざまなロックのオーバーヘッドとアプリケーションシナリオを知る必要があります。

次に、これらの一般的なロックについて説明しましょう。


テキスト

マルチスレッドが共有リソースにアクセスする場合、リソースの競合によるデータの乱れの問題は避けられないため、この問題を解決するために、通常は共有リソースにアクセスする前にロックします。

最も一般的に使用されるのは相互除外ロックです。もちろん、スピンロック、読み取り/書き込みロック、楽観的ロックなど、さまざまな種類のロックがあります。さまざまな種類のロックがさまざまなシナリオに適しています。

間違ったロックを選択すると、同時実行性の高いシナリオでは、システムのパフォーマンスが低下し、ユーザーエクスペリエンスが非常に低下する可能性があります。

したがって、適切なロックを選択するには、ロックのコストを知るだけでなく、ビジネスシナリオで共有リソースにアクセスする方法を分析する必要があります。次に、共有リソースに同時にアクセスするときの競合の可能性も考慮する必要があります。

適切な薬を処方することによってのみ、高い同時実行パフォーマンスに対するロックの影響を減らすことができます。

次に、さまざまなアプリケーションシナリオについて相互除外ロック、スピンロック、読み取り/書き込みロック、楽観的ロック、および悲観的ロック」の選択と使用について説明します。

ミューテックスとスピンロック:誰がより快適ですか?

下の2つは「相互排除ロックとスピンロック」であり、それらに基づいて多くの高度なロックが実装されています。これらはさまざまなロックの基盤と考えることができるため、2つの違いを明確にする必要があります。そしてアプリケーション。

ロックの目的は、共有リソースが常に1つのスレッドのみによってアクセスされるようにすることです。これにより、複数のスレッドによって引き起こされる共有データの混乱の問題を回避できます。

1つのスレッドがロックされると、他のスレッドはロックに失敗します。相互除外ロックとスピンロックは、ロックに失敗した後の処理が異なります。

  • ミューテックスロックが失敗した後、スレッドはCPU解放し、 他のスレッドに渡します。
  • スピンロックロックに失敗した後、スレッドはロックを取得するまで待機します。

ミューテックスは一種の「排他的ロック」です。たとえば、スレッドAが正常にロックされると、ミューテックスはすでにスレッドAによって占有されています。スレッドAが手元のロックを解放しない限り、スレッドBはロックに失敗します。 CPUは他のスレッドに解放されます。スレッドBはCPUを解放するため、スレッドBによってロックされたコードはブロックされます。

ミューテックスロックの失敗とブロッキングの現象は、オペレーティングシステムカーネルによって実現されますロックが失敗すると、カーネルはスレッドを「スリープ」状態にします。ロックが解除された後、カーネルは適切なタイミングでスレッドをウェイクアップします。スレッドがロックを正常に取得すると、実行を続行できます。以下に示すように:

したがって、ミューテックスロックが失敗すると、ユーザーモードからカーネルモードになり、カーネルにスレッドを切り替えさせます。ロックの使用の難しさは単純化されますが、パフォーマンスのオーバーヘッドコストが一定になります。

では、このオーバーヘッドコストはいくらですか?ありますスレッドコンテキストの切り替えの2つのコスト

  • スレッドがロックに失敗すると、カーネルはスレッドの状態を「実行中」状態から「スリープ」状態に設定し、CPUを他のスレッドに切り替えて実行します。
  • 次に、ロックが解除されると、「スリープ」状態にあったスレッドが「準備完了」状態になり、カーネルはCPUをスレッドに切り替えて適切なタイミングで実行します。

スレッドのコンテキストスイッチとは何ですか?2つのスレッドが同じプロセスに属している場合、仮想メモリが共有されるため、切り替え時に仮想メモリのリソースはそのまま残り、スレッドで共有されていないプライベートデータ、レジスタ、およびその他のデータのみを切り替える必要があります。

切り替えに費やされた時間は大物によって数えられています。おそらく数十ナノ秒から数マイクロ秒の間です。ロックされたコードの実行時間が比較的短い場合、コンテキストの切り替え時間はロックされたコードの実行時間よりも長くなる可能性があります。それはさらに長いです。

したがって、ロックされたコードの実行時間が非常に短いことが確実な場合は、ミューテックスロックではなく、スピンロックを使用する必要があります。それ以外の場合は、ミューテックスロックを使用してください。

スピンロックはCPU CAS (Compare And Swap)が提供する 機能で、「ユーザーモード」でロックとロック解除の操作を完了し、スレッドコンテキストの切り替えをアクティブに生成しないため、ミューテックスロックと比較して高速でコストがかかります。小さい。

一般的なロックプロセスは、次の2つのステップで構成されます。

  • 最初のステップは、ロックのステータスを確認することです。ロックが解放されている場合は、2番目のステップを実行します。
  • 2番目のステップは、現在のスレッドによって保持されるようにロックを設定することです。

CAS関数は、これら2つのステップをハードウェアレベルの命令にマージしてアトミック命令を形成します。これにより、2つのステップが分離できないことが保証されます。2つのステップが同時に実行されるか、両方のステップが実行されません。

スピンロックを使用する場合、ロックのマルチスレッド競合が発生すると、ロックに失敗したスレッドは、ロックを取得するまで「ビジー待機」します。ここでの「ビジー待機」はwhile サイクリック待機で実現できます、 サイクリック待機PAUSE 時の消費電力を削減できるため、CPUの指示で「ビジー待機」を実現するのが最適 です。

スピンロックは最も単純なタイプのロックで、ロックが使用可能になるまで回転を続け、CPUサイクルを使用します。シングルコアCPUでは、プリエンプティブスケジューラが必要であることに注意してください(つまり、1つのスレッドが他のスレッドを実行するためにクロックによって継続的に中断されます)。そうしないと、回転するスレッドがCPUを放棄することがないため、単一のCPUでスピンロックを使用できません。

スピンロックのオーバーヘッドは低く、通常、マルチコアシステムではスレッドの切り替えはアクティブに行われません。ユーザーモードの切り替え要求での非同期、通常、その他のプログラミング方法に適しています。ただし、ロックされたコードの実行時間が長すぎると、スピンするスレッドはCPUリソースを長時間消費するため、スピン時間とロックされたコードの実行時間は「比例」関係にあります。これを明確に知る必要があります。

スピンロックとミューテックスの使用レベルは似ていますが、実装レベルは完全に異なります。ロックが失敗すると、ミューテックスは「スレッドスイッチング」を使用して処理し、スピンロックは「ビジー待機」を使用して処理します

これら2つはロックの最も基本的な処理方法であり、より高度なロックでは、実装するものを1つ選択します。たとえば、読み取り/書き込みロックは、ミューテックスロックまたはスピンロックに基づいて実装できます。


読み取り/書き込みロック:読み取りと書き込みの間に優先順位の違いはありますか?

読み取り/書き込みロックの文字通りの意味から、「読み取りロック」と「書き込みロック」の2つの部分で構成されていることもわかります。共有リソースのみを読み取る場合は「読み取りロック」を使用してロックし、共有リソースを変更する場合は「書き込みロック」を使用します。 「ロックされています。

したがって、読み取り/書き込みロックは、読み取り操作と書き込み操作を明確に区別できるシナリオに適しています

読み取り/書き込みロックの動作原理は次のとおりです。

  • 「書き込みロック」がスレッドによって保持されていない場合、複数のスレッドが読み取りロックを同時に保持できるため、共有リソースのアクセス効率が大幅に向上します。「読み取りロック」は共有リソースの読み取りに使用されるため、非常に多くの読み取りロックを同時に保持しているスレッドは、共有リソースのデータを破壊しません。
  • ただし、スレッドが「書き込みロック」を保持すると、リーダースレッドの読み取りロック取得操作がブロックされ、他の書き込みスレッドの書き込みロック取得操作もブロックされます。

したがって、ミューテックスやスピンロックと同様に、書き込みロックは常に1つのスレッドのみが書き込みロックを保持できるため、書き込みロックは排他ロックです。一方、読み取りロックは、複数のスレッドが同時に保持できるため、共有ロックです。

読み取り/書き込みロックの動作原理を理解した後、読み取り/書き込みロックは、より多くの読み取りとより少ない書き込みのシナリオでその利点を発揮できることがわかります

さらに、さまざまな実装に応じて、読み取り/書き込みロックは「読み取り優先ロック」と「書き込み優先ロック」に分けることができます。

読み取り優先ロックの期待は、リーダースレッドの同時実行性を向上させるために、より多くのスレッドが読み取りロックを保持できることです。これは次のように機能します。リーダースレッドAが最初に読み取りロックを保持すると、ライタースレッドBが書き込みロックを取得します。ブロッキングプロセスでは、後続のリーダースレッドCは引き続き読み取りロックを正常に取得できます。最後に、リーダースレッドAとCが読み取りロックを解放した後、書き込みスレッドBは書き込みロックを正常に取得できます。以下に示すように:

書き込み優先度ロックは、書き込みスレッドにサービスを提供する優先度です。その動作方法は、リーダースレッドAが最初に読み取りロックを保持すると、書き込みロックを取得するときに書き込みスレッドBがブロックされ、ブロックプロセス中に後続の読み取りがブロックされます。スレッドCは読み取りロックの取得に失敗するため、読み取りロックを取得する操作でリーダースレッドCがブロックされ、リーダースレッドAが読み取りロックを解放している限り、書き込みスレッドBは読み取りロックを正常に取得できます。以下に示すように:

読み取り優先ロックはスレッドの同時実行性を読み取るのに適していますが、問題がないわけではありません。リーダースレッドが常に読み取りロックを取得する場合、ライタースレッドが書き込みロックを取得することはなく、ライタースレッドの「枯渇」が発生するとします。

書き込み優先ロックは、ライタースレッドが枯渇しないようにすることができますが、書き込みロックを取得するライタースレッドが常に存在する場合、リーダースレッドも「飢餓状態」になります。

優先読み取りロックまたは書き込みロックに関係なく、相手が餓死する可能性があるため、いずれの当事者も優先せず、「公正な読み取り/書き込みロック」を実行します。

公正な読み取り/書き込みロックの比較的簡単な方法は、ロックを取得するスレッドをキューでキューに入れることです。ライタースレッドであろうとリーダースレッドであろうと、ファーストイン、ファーストアウトの原則に従ってロックできるため、リーダースレッドは引き続き並行できますが、同時ではありません。 「空腹」という現象があります。

ミューテックスロックとスピンロックの両方が最も基本的なロックです。読み取り/書き込みロックは、シナリオに応じてこれら2つのロックのいずれかを選択することで実装できます。


楽観的ロックと悲観的ロック:物事を行う精神の違いは何ですか?

前述のミューテックス、スピンロック、および読み取り/書き込みロックはすべて悲観的なロックです。

ペシミスティックロックはよりペシミスティックです。複数のスレッドが共有リソースを同時に変更する可能性が比較的高いため、競合が発生しやすいため、共有リソースにアクセスする前に、まずロックする必要があります

逆に、複数のスレッドが共有リソースを同時に変更する可能性が比較的低い場合は、楽観的なロックを使用できます。

楽観的ロックの方が楽観的です。競合の可能性が非常に低いことを前提としています。その作業方法は、最初に共有リソースを変更してから、この期間中に競合があるかどうかを確認することです。他のスレッドがリソースを変更していない場合、操作は完了です。他のスレッドがこのリソースを変更したことが判明したため、この操作は中止されました

諦めた後の再試行方法は、ビジネスシナリオと密接に関係しており、再試行のコストは高くなりますが、競合の可能性が十分に低い場合は許容されます。

Optimistic Lockの考え方は、スリーセブンワンに関係なく、最初にリソースを変更することであることがわかります。さらに、楽観的ロックはプロセス全体でロックされていないため、ロックフリープログラミングとも呼ばれます

シナリオの例を次に示します:オンラインドキュメント。

オンラインドキュメントは複数の人が同時に編集できることは誰もが知っています。ペシミスティックロックを使用すると、1人のユーザーがドキュメントを編集している限り、他のユーザーが同じドキュメントを開くことはできません。もちろん、ユーザーエクスペリエンスは良くありません。

複数の人による同時編集を実現するには、実際には楽観的ロックを使用します。これにより、複数のユーザーが同じドキュメントを開いて編集し、編集および送信後に変更されたコンテンツが競合するかどうかを確認できます。

何が競合としてカウントされますか?例を次に示します。たとえば、ユーザーAは最初にブラウザーでドキュメントを編集し、次にユーザーBは編集のためにブラウザーで同じドキュメントを開きますが、ユーザーBはユーザーAよりも変更を送信します。ユーザーAはこのプロセスを知りません。 Aが変更されたコンテンツを送信すると、並行変更でAとBの間に競合が発生します。

サーバーは競合があるかどうかをどのように確認しますか?通常のスキームは次のとおりです。

  • 競合の可能性は比較的低いため、最初にユーザーにドキュメントを編集させますが、ブラウザはドキュメントのダウンロード時にサーバーから返されたドキュメントのバージョン番号を記録します。
  • ユーザーが変更を送信すると、サーバーに送信されたリクエストには元のドキュメントのバージョン番号が含まれます。サーバーはそれを受信すると、現在のバージョン番号と比較します。バージョン番号が同じ場合は変更が成功し、そうでない場合は送信が失敗します。

実際、私たちの一般的なSVNとGitも楽観的なロックのアイデアを使用しています。まず、ユーザーがコードを編集できるようにし、送信時にバージョン番号を使用して競合があるかどうかを判断します。競合が発生した場合は、自分で変更する必要があります。もう一度送信してください。

楽観的ロックはロックとロック解除の操作を削除しますが、競合が発生すると再試行のコストが非常に高くなるため、競合の可能性が非常に低く、ロックのコストが非常に高いシナリオでのみ、楽観的ロックを検討する必要があります。


総括する

開発プロセスで最も一般的なのはミューテックスロックです。ミューテックスロックが失敗すると、「スレッド切り替え」を使用して処理します。ロックをロックできなかったスレッドが再び正常にロックされると、2つになります。セカンダリスレッドコンテキストスイッチングのコスト、パフォーマンスの低下は比較的大きいです。

ロックされたコードの実行時間が非常に短いことが明確にわかっている場合は、オーバーヘッドが比較的小さいスピンロックを選択する必要があります。これは、スピンロックがロックに失敗すると、スレッドスイッチングがアクティブに生成されないが、待機に忙しいためです。ロックが取得されるまで、ロックされたコードの実行時間が短い場合、それに応じてビジー待機時間も短くなります。

読み取り操作と書き込み操作を区別できる場合は、読み取り/書き込みロックの方が適切です。これにより、複数のリーダースレッドが同時に読み取りロックを保持できるため、読み取りの同時実行性が向上します。リーダーまたはライターの好みに応じて、読み取り優先ロックと書き込み優先ロックに分けることができます。読み取り優先ロックは同時実行性が強いですが、書き込みスレッドは枯渇し、書き込み優先ロックは書き込みスレッドを優先し、読み取りスレッドも優先する場合があります。飢餓状態になるために、飢餓の問題を回避するために、ロックを要求するスレッドをキューに入れるためにキューを使用し、スレッドをロックするためのファーストイン、ファーストアウトの原則を保証する公正な読み取り/書き込みロックがあります。スレッドが枯渇することはなく、汎用性が向上します。

ミューテックスロックとスピンロックの両方が最も基本的なロックです。読み取り/書き込みロックは、シナリオに応じてこれら2つのロックのいずれかを選択することで実装できます。

また、ミューテックス、スピンロック、読み取り/書き込みロックはすべてペシミスティックロックです。ペシミスティックロックは、共有リソースに同時にアクセスする場合、競合の可能性が非常に高いと考えているため、共有リソースにアクセスする前に、まずロックする必要があります。

逆に、共有リソースに同時にアクセスするときに競合の可能性が非常に低い場合は、楽観的なロックを使用できます。共有リソースにアクセスするときは、最初にロックする必要はありません。共有リソースを変更した後、この期間を確認してください。競合があるかどうかに関係なく、他のスレッドがリソースを変更していない場合、操作は完了します。他のスレッドがリソースを変更していることが判明した場合、操作は中止されます。

ただし、競合の可能性が高くなると、競合を解決するための再試行コストが非常に高くなるため、楽観的ロックを使用することは適切ではありません。

どのような種類のロックを使用する場合でも、ロックコードの範囲をできるだけ小さくする必要があります。つまり、実行速度を上げるために、ロックの粒度を小さくする必要があります。次に、適切なロックを使用すると、速度が上がります。

 


まとめた面接の質問と、教材やマインドマップのまとめを組み合わせました。マップはごく一部です。今、それをみんなに無料で渡してください。方法:クリックして秘密のコードを一緒に学ぶ:csdn    

無料のビデオ学習資料: 第一線のメーカーのコアテクノロジーの共有

フォローアップでより純粋な乾物の記事を共有し、本当にあなたを助けたいと思っています。あなたの[サンリアン]サポートは私の最大の動機です!提案は大歓迎です!

おすすめ

転載: blog.csdn.net/weixin_50333534/article/details/109081573