両方が同じ仕事をしていると思いますが、同期に使用するものをどのように決定しますか?
両方が同じ仕事をしていると思いますが、同期に使用するものをどのように決定しますか?
回答:
理論
理論的には、スレッドがミューテックスをロックしようとして成功しない場合、ミューテックスはすでにロックされているため、スリープ状態になり、すぐに別のスレッドを実行できます。目覚めるまでスリープ状態を続けます。これは、以前にロックを保持していたスレッドによってミューテックスがロック解除された場合に当てはまります。スレッドがスピンロックをロックしようとして成功しなかった場合、最終的に成功するまで、継続的にロックを再試行します。したがって、別のスレッドに代わることはできません(ただし、もちろん、現在のスレッドのCPUランタイムクォンタムを超えると、オペレーティングシステムは強制的に別のスレッドに切り替わります)。
問題
ミューテックスの問題は、スレッドをスリープ状態にして再び起動することはどちらもかなりコストのかかる操作であり、CPU命令を大量に必要とするため、時間がかかることです。ミューテックスが非常に短い時間だけロックされている場合、スレッドをスリープ状態にして再度ウェイクアップするのに費やされた時間は、スレッドが実際にスリープした時間を超える可能性があり、スレッドの時間を超える可能性さえありますスピンロックを常にポーリングすることで無駄になっています。一方、スピンロックのポーリングは常にCPU時間を浪費し、ロックが長時間保持されていると、CPU時間をかなり浪費し、スレッドが代わりにスリープ状態になっている場合ははるかに良くなります。
ソリューション
シングルコア/シングルCPUシステムでスピンロックを使用しても、通常は意味がありません。スピンロックポーリングが利用可能な唯一のCPUコアをブロックしている限り、他のスレッドは実行できず、他のスレッドは実行できないため、ロックは実行されません。ロック解除されます。IOW、スピンロックは、実際の利益のためにそれらのシステムのCPU時間のみを浪費します。代わりにスレッドがスリープ状態に置かれた場合、別のスレッドが一度に実行され、おそらくロックが解除され、最初のスレッドが再び目覚めたときに処理を続行できる可能性があります。
マルチコア/マルチCPUシステムでは、非常に短時間だけ保持されるロックがたくさんあるため、常にスレッドをスリープ状態にして再度ウェイクアップするために費やされる時間が無駄になり、ランタイムパフォーマンスが著しく低下する可能性があります。代わりにスピンロックを使用すると、スレッドは完全なランタイムクォンタムを利用する機会を得ます(常に非常に短い期間だけブロックし、その後すぐに作業を続行します)。これにより、処理スループットが大幅に向上します。
練習
多くの場合、プログラマーはmutexまたはスピンロックの方が優れているかどうかを事前に知ることができないため(たとえば、ターゲットアーキテクチャのCPUコアの数が不明であるため)、オペレーティングシステムが特定のコードがシングルコアまたはマルチコア環境では、ほとんどのシステムはミューテックスとスピンロックを厳密に区別しません。実際、最近のほとんどのオペレーティングシステムには、ハイブリッドmutexとハイブリッドスピンロックがあります。それは実際にはどういう意味ですか?
ハイブリッドミューテックスは、マルチコアシステムでは最初はスピンロックのように動作します。スレッドがmutexをロックできない場合、mutexはすぐにロック解除される可能性があるため、スレッドはすぐにはスリープ状態になりません。代わりに、mutexはまずスピンロックのように動作します。一定の時間(または再試行またはその他の測定要素)が経過してもロックがまだ取得されない場合にのみ、スレッドは実際にスリープ状態になります。シングルコアのみのシステムで同じコードが実行される場合、ミューテックスはスピンロックしませんが、上記のように、それは有益ではありません。
ハイブリッドスピンロックは、最初は通常のスピンロックのように動作しますが、CPU時間を浪費しすぎないようにするために、バックオフ戦略が考えられます。これは通常、スレッドをスリープ状態にしません(スピンロックを使用しているときに発生しないようにするため)が、スレッドを停止して(すぐに、または一定の時間が経過した後)、別のスレッドの実行を許可する場合があります、したがって、スピンロックがロック解除される可能性が高くなります(純粋なスレッドスイッチは通常、スレッドをスリープ状態にして後で再びウェイクアップするものよりも安価ですが、それほど遠くないですが)。
概要
疑わしい場合は、ミューテックスを使用してください。ミューテックスは通常、より良い選択です。最近のほとんどのシステムでは、有益であると思われる場合に、非常に短い時間でスピンロックできます。スピンロックを使用するとパフォーマンスが向上する場合がありますが、特定の条件下で疑わしいという事実がある場合にのみ、現在スピンロックが有益である可能性のあるプロジェクトに取り組んでいないことがわかります。内部でスピンロックまたはミューテックスを使用できる独自の「ロックオブジェクト」の使用を検討する場合があります(たとえば、このようなオブジェクトを作成するときにこの動作を構成できます)。最初はどこでもミューテックスを使用し、どこかでスピンロックを使用すると実際にはヘルプ、試して、結果を比較します(たとえば、プロファイラーを使用)。ただし、両方のケースをテストしてください。
実際にはiOS固有ではありませんが、iOSはほとんどの開発者がこの問題に直面する可能性のあるプラットフォームです。システムにスレッドスケジューラがある場合、スレッドの優先度がどれほど低くても、最終的には実行される可能性があるという保証はありません。その後、スピンロックは永続的なデッドロックを引き起こす可能性があります。iOSスケジューラーは異なるクラスのスレッドを区別し、下位クラスのスレッドは、上位クラスのスレッドも実行したくない場合にのみ実行されます。これにはバックオフ戦略がないため、高クラスのスレッドを永続的に使用できる場合、低クラスのスレッドがCPU時間を取得することがないため、作業を実行する機会がありません。
問題は次のように表示されます。コードは低プリオクラススレッドでスピンロックを取得し、そのロックの最中にタイムクォンタムを超えたため、スレッドは実行を停止します。このスピンロックを再び解放できる唯一の方法は、低プリオクラスのスレッドが再びCPU時間を取得する場合ですが、これが起こるとは限りません。常に実行したい高優先度クラスのスレッドがいくつかあり、タスクスケジューラは常にそれらを優先します。それらの1つがスピンロックを横切って実行し、それを取得しようとする可能性がありますが、これはもちろん不可能であり、システムはそれを生成します。問題は、生成されたスレッドがすぐに再び実行できるようになることです。ロックを保持しているスレッドよりも優先順位が高いため、ロックを保持しているスレッドはCPUランタイムを取得する機会がありません。
この問題がミューテックスでは発生しないのはなぜですか?ハイプリオスレッドがミューテックスを取得できない場合、ミューテックスは生成されません。少し回転する可能性がありますが、最終的にはスリープ状態になります。スリープ状態のスレッドは、イベント(たとえば、ミューテックスがロック解除されているなどのイベント)によってウェイクアップされるまで、実行できません。Appleはその問題を認識してOSSpinLock
おり、結果として非推奨になりました。新しいロックはと呼ばれos_unfair_lock
ます。このロックは、異なるスレッド優先度クラスを認識しているため、上記の状況を回避します。iOSプロジェクトでスピンロックを使用することが適切であると確信している場合は、それを使用してください。近づかないOSSpinLock
!また、iOSで独自のスピンロックを実装することは決してありません。疑わしい場合は、ミューテックスを使用してください。macOSは、スレッド(低プリオスレッドであっても)がCPU時間で「ドライ」することを許可しない別のスレッドスケジューラーを備えているため、この問題の影響を受けません。それでも同じ状況が発生し、非常に貧弱になる可能性があります。したがってOSSpinLock
、macOSでも非推奨となっています。
Meckiの提案を続けて、Alexander Sandlerのブログのこの記事pthread mutexとpthreadスピンロック、Linux上のAlexは、#ifdefを使用して動作をテストするためにspinlock
&mutexes
を実装する方法を示しています。
ただし、得られた例は孤立したケースであり、プロジェクトの要件や環境がまったく異なる場合があるので、観察に基づいて最後の呼び出しを行うようにしてください。
特定の環境や条件(ディスパッチレベル> = DISPATCH LEVELのウィンドウで実行するなど)では、ミューテックスを使用できず、スピンロックを使用することにも注意してください。UNIXでも同じです。
競合他社のstackexchange UNIXサイトでの同等の質問は次のとおりです。https://unix.stackexchange.com/questions/5107/why-are-spin-locks-good-choices-in-linux-kernel-design-instead-of-something- もっと
Windowsシステムでのディスパッチに関する情報:http : //download.microsoft.com/download/e/b/a/eba1050f-a31d-436b-9281-92cdfeae4b45/IRQL_thread.doc
メッキーの答えはかなりうまくいきます。ただし、シングルプロセッサでは、タスクがロックが割り込みサービスルーチンによって与えられるのをタスクが待機しているときに、スピンロックを使用することが理にかなっている場合があります。割り込みにより、ISRに制御が移り、待機中のタスクがリソースを使用できるようになります。中断されたタスクに制御を戻す前にロックを解放することで終了します。回転タスクは、スピンロックが使用可能であることを検出して続行します。
スピンロックとミューテックスの同期メカニズムは、今日見られるように非常に一般的です。
まず、スピンロックについて考えてみましょう。
基本的にビジーな待機アクションです。つまり、次のアクションに進む前に、指定されたロックが解放されるまで待機する必要があります。概念的には非常に単純ですが、実装はケースにありません。例:ロックが解放されていない場合、スレッドはスワップアウトされてスリープ状態になりましたが、それに対処する必要がありますか?2つのスレッドが同時にアクセスを要求した場合の同期ロックの扱い方
一般に、最も直感的なアイデアは、クリティカルセクションを保護するために変数を介して同期を処理することです。ミューテックスの概念は似ていますが、まだ異なります。焦点:CPU使用率。スピンロックは、アクションの実行を待機するためにCPU時間を消費するため、2つの違いを合計できます。
均質なマルチコア環境で、クリティカルセクションに費やす時間がスピンロックを使用するよりも小さい場合、コンテキスト切り替え時間を短縮できるためです。(一部のシステムでは、スイッチの真ん中にスピンロックが実装されているため、シングルコアの比較は重要ではありません)
Windowsでは、Spinlockを使用するとスレッドがDISPATCH_LEVELにアップグレードされます。DISPATCH_LEVELは許可されない場合があるため、今回はMutex(APC_LEVEL)を使用する必要がありました。
シングルコア/シングルCPUシステムでスピンロックを使用しても、通常は意味がありません。スピンロックポーリングが利用可能な唯一のCPUコアをブロックしている限り、他のスレッドは実行できず、他のスレッドは実行できないため、ロックは実行されません。ロック解除されます。IOW、スピンロックは、実際の利益のためにそれらのシステムでCPU時間のみを浪費します
これは間違っています。プロセスがスピンロックを取得すると、プリエンプションが無効になるため、他のユーザーがスピンすることはないため、ユニプロセッサシステムでスピンロックを使用してもCPUサイクルの無駄はありません。それを使用しても意味がないというだけです!したがって、Uniシステムのスピンロックは、コンパイル時にカーネルによってpreempt_disableに置き換えられます。